Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile-time literal string as template argument

I'm trying to convert a C++ literal string into an instance of the following template:

template <char ... C>
struct string_literal {
    typedef string_constant type;
    static constexpr const char value[sizeof...(C)] = {C...};
    constexpr operator const char* (void) const {
        return value;
    }
};
template <char ... C>
constexpr const char string_literal<C...>::value[sizeof...(C)];

I came up with these helpers based on various sources for 'unpacking' the quoted string value into the template above.

template <unsigned N, const char (&S) [N], typename U>
struct selector;

template <unsigned N, const char (&S) [N], unsigned ...I>
struct selector<N, S, index_sequence<I...>> {
    using type = string_literal<S[I]...>;
};

template <unsigned N, const char (&S) [N]>
struct unpack {
    using type = typename selector<N, S, make_index_sequence<N>>::type;
};

However, when a call this I get a compiler error:

template <unsigned N>
constexpr auto make_string_literal(const char (&s) [N]) {
    return unpack<N, s>{}; // Error here
}

constexpr auto literal = make_string_literal("test");
// string_literal<'t','e','s','t','\0'>

GCC 4.9+ reports: error: 'const char (& s)[1]' is not a valid template argument for type 'const char (&)[1]' because a reference variable does not have a constant address

Clang 3.7.1 reports: error: non-type template argument refers to object 's' that does not have linkage

I tried a few different approaches but the errors are mostly the same. What am I missing here?

like image 777
Ricardo Andrade Avatar asked Oct 30 '22 08:10

Ricardo Andrade


1 Answers

Is this a satisfactory solution to meet your needs?

template <char ... C>
struct string_literal {
    static constexpr const char value[sizeof...(C)] = {C...};
    constexpr operator const char* (void) const {
        return value;
    }
    void foo() {std::cout << value << '\n';}
};
template <char ... C> constexpr const char string_literal<C...>::value[sizeof...(C)];

template <typename CharT, CharT... Cs>
constexpr string_literal<Cs...> operator ""_create() {
    return {};
}

int main() {
    string_literal<'t','e','s','t'> s = "test"_create;
    std::cout << s << '\n';  // test
    s.foo();  // test
}
like image 131
prestokeys Avatar answered Nov 08 '22 16:11

prestokeys