Unable to create string literal

I want to make a string literal that I can use as a template argument. It throws the compiler into some infinite loop. What is the problem and fix?

template <char...> struct slit { }; template <typename ...A> constexpr auto make_slit(char const* const s, A const ...args) { return *s ? make_slit(s + 1, *s, args...) : slit<args...>(); } int main() { auto const tmp_(make_slit("slit")); return 0; } 

Mandatory error (with clang++ -std=c++1y ):

 t.cpp:4:16: fatal error: recursive template instantiation exceeded maximum depth of 256 constexpr auto make_slit(char const* const s, A const ...args) ^ t.cpp:6:15: note: in instantiation of function template specialization 'make_slit<char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char, char>' requested here return *s ? make_slit(s + 1, *s, args...) : slit<args...>(); 
+6
source share
2 answers

By delaying the creation of a loop, you cannot achieve what you want, since the function parameter cannot be used as the constant expression that is required for the template arguments. The following is also not allowed:

 template <typename... A> constexpr auto make_slit(A const... args) { return slit<args...>(); } // error make_slit('a'); 

If you find this surprisingly, keep in mind that constexpr functions are a function that allows some functions to also be used in constant expression. In general, you do not have:

 char c; std::cin >> c; // what is the result type? make_slit(c); 

It should be noted, however, that when designing literal string operators, it was suggested to allow the form of the function template (as well as for integers and floating point numbers), which would provide exactly what you need:

 // allowed... template<char... Cs> constexpr slit<Cs...> operator"" _slit() { return {}; } // ...but only for auto constexpr s = 123_slit; auto constexpr t = 12.3_slit; // ... and not auto constexpr u = "abc"_slit; 

This missing functionality was raised most recently in 2013 with Richard Smiths n3599: Literal Operator Patterns for Strings . Unfortunately, I do not know what the current status of the function is.

+3
source

You can find a solution to expand the string literal into the parameter package here

 #include <iostream> // c++14 has it http://en.cppreference.com/w/cpp/utility/integer_sequence namespace detail { template <int... Is> struct seq { }; template <int N, int... Is> struct gen_seq : gen_seq<N - 1, N - 1, Is...> { }; template <int... Is> struct gen_seq<0, Is...> : seq<Is...> { }; } constexpr size_t operator"" _len ( const char*, size_t len ){ return len; } template < char... val > struct slit {}; #define EXPAND_STRING( type_name, str ) \ template <int... Is> slit< str[Is]...> make_##type_name( detail::seq<Is...> ); \ using type_name = decltype( make_##type_name( detail::gen_seq<str##_len>{} ) ); using Manual = slit< 'b', 'a', 'z'>; EXPAND_STRING( MyFoo, "foo bar baz"); EXPAND_STRING( MyBar, "bla bli blo blu"); inline std::ostream& operator<<( std::ostream& os, slit<> ) { return os; } template < char first, char... chars > std::ostream& operator<<( std::ostream& os, slit<first,chars...> ) { return os << first << " " << slit<chars...>{}; } int main() { std::cout << Manual{} << "\n"; std::cout << MyFoo{} << "\n"; std::cout << MyBar{} << "\n"; } 

EDIT: replaced constexpr strlen with its own literal, it returns the length directly and removes the dependency using the relaxed constexpr function from C ++ 1y.

+3
source

All Articles