So che il post è vecchio, ma non ho trovato alcuna soluzione per questo problema qui, e forse qualcuno sarebbe interessato a mia soluzione:
template <int N>
constexpr int string_literal_length(const char (&str)[N]) {
return N - 1;
}
template <int PassedLength, int CountedLength, char... Characters>
struct string_literal {
static_assert(PassedLength == CountedLength, "Passed to STRING_LITERAL length does not match the length of string...");
};
#define STRING_LITERAL(N, str) string_literal<N, string_literal_length(str), STRING_LITERAL_##N(str)>
// ... as long as we need it ...
#define STRING_LITERAL_128(str) STRING_LITERAL_127(str), str[127]
#define STRING_LITERAL_127(str) STRING_LITERAL_126(str), str[126]
#define STRING_LITERAL_126(str) STRING_LITERAL_125(str), str[125]
#define STRING_LITERAL_125(str) STRING_LITERAL_124(str), str[124]
// ...
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), str[4]
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), str[3]
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), str[2]
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), str[1]
#define STRING_LITERAL_1(str) str[0]
Ora utilizzo:
template <class SLiteral>
struct usage_of_string_literal {
};
int main() {
usage_of_string_literal<STRING_LITERAL(12, "123456789012")> uosl;
}
Purtroppo uno sono tenuti a fornire la lunghezza della stringa per farlo funzionare ma e' s ancora la soluzione più comoda rispetto alla semplice variadic modello arg di caratteri, e la lunghezza è verificata dal static_assert in modo che il compilatore può aiutare a prendere valore appropriato ...
Modifica
Un altro modello Magia. Questo è facendo uso di corto circuito per eliminare delle dimensioni stringa dalla stringa-dichiarazione (C++ 17):
#include <type_traits>
#include <utility>
#define MAX_STRING_LITERAL_LENGTH 11
#define STRING_LITERAL(str) string_literal<char_pack<STRING_LITERAL_11(str)>>::s
#define STRING_LITERAL_11(str) STRING_LITERAL_10(str), ((TERMINATED_10(str))?(str[10]):('\0'))
#define STRING_LITERAL_10(str) STRING_LITERAL_9(str), ((TERMINATED_9(str))?(str[9]):('\0'))
#define STRING_LITERAL_9(str) STRING_LITERAL_8(str), ((TERMINATED_8(str))?(str[8]):('\0'))
#define STRING_LITERAL_8(str) STRING_LITERAL_7(str), ((TERMINATED_7(str))?(str[7]):('\0'))
#define STRING_LITERAL_7(str) STRING_LITERAL_6(str), ((TERMINATED_6(str))?(str[6]):('\0'))
#define STRING_LITERAL_6(str) STRING_LITERAL_5(str), ((TERMINATED_5(str))?(str[5]):('\0'))
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), ((TERMINATED_4(str))?(str[4]):('\0'))
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), ((TERMINATED_3(str))?(str[3]):('\0'))
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), ((TERMINATED_2(str))?(str[2]):('\0'))
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), ((TERMINATED_1(str))?(str[1]):('\0'))
#define STRING_LITERAL_1(str) str[0]
#define TERMINATED_10(str) TERMINATED_9(str) && str[9]
#define TERMINATED_9(str) TERMINATED_8(str) && str[8]
#define TERMINATED_8(str) TERMINATED_7(str) && str[7]
#define TERMINATED_7(str) TERMINATED_6(str) && str[6]
#define TERMINATED_6(str) TERMINATED_5(str) && str[5]
#define TERMINATED_5(str) TERMINATED_4(str) && str[4]
#define TERMINATED_4(str) TERMINATED_3(str) && str[3]
#define TERMINATED_3(str) TERMINATED_2(str) && str[2]
#define TERMINATED_2(str) TERMINATED_1(str) && str[1]
#define TERMINATED_1(str) str[0]
template <char... Cs>
struct char_pack {
static constexpr char const arr[sizeof...(Cs) + 1] = {Cs..., 0};
static constexpr std::size_t non_zero_count = (((Cs != 0)?1:0) + ...);
static_assert(non_zero_count < MAX_STRING_LITERAL_LENGTH, "You need to create more macros");
};
template <char... Cs>
constexpr char const char_pack<Cs...>::arr[sizeof...(Cs) + 1];
template <char... Cs>
constexpr std::size_t char_pack<Cs...>::non_zero_count;
template <class CP, class = void, class = std::make_index_sequence<CP::non_zero_count>>
struct string_literal;
template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>> {
static constexpr char const s[sizeof...(Cs) + 1] = {Cs..., '\0'};
};
template <char... Cs, std::size_t... Is>
constexpr char const string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>>::s[sizeof...(Cs) + 1];
template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<!(Cs && ...)>, std::index_sequence<Is...>>: string_literal<char_pack<char_pack<Cs...>::arr[Is]...>> { };
template <const char *>
struct foo {};
int main() {
foo<STRING_LITERAL("abcdefghij")> f;
static_cast<void>(f);
}
[live demo]
Nel primo caso, 'String ("ciao")' è un valore, non un tipo, quindi non può essere passato al template 'Get <>' che si aspetta un tipo. Nel secondo caso, C++ 11 non consente che i tipi arbitrari definiti dall'utente (come 'String') siano parametri del modello. –