I'd like to make a string literal I can use as a template argument. It throws the compiler into some kind of endless 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;
}
The obligatory 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...>();
EDIT: check out this answer, generating compile time slit types is possible.
The best way to declare a string literal in your code is to use array notation, like this: char string[] = "I am some sort of interesting string. \n"; This type of declaration is 100 percent okey-doke.
Modifying a string literal frequently results in an access violation because string literals are typically stored in read-only memory. (See undefined behavior 33.) Avoid assigning a string literal to a pointer to non- const or casting a string literal to a pointer to non- const .
The string literal type allows you to specify a set of possible string values for a variable, only those string values can be assigned to a variable. TypeScript throws a compile-time error if one tries to assign a value to the variable that isn't defined by the string literal type.
A string literal can be created by writing a text(a group of Characters ) surrounded by a single(”), double(“”), or triple quotes. By using triple quotes we can write multi-line strings or display them in the desired way. Example: Here geekforgeeks is a string literal that is assigned to a variable(s).
Putting aside the looping instantiation, you cannot achieve what you want as a function parameter cannot be used as a constant expression, which is required of template arguments. Meaning the following is not allowed either:
template <typename... A>
constexpr auto make_slit(A const... args)
{
return slit<args...>();
}
// error
make_slit('a');
If you find this surprising, keep in mind that constexpr functions are a feature to allow some functions to also be usable in a constant expression. Yours isn’t in general however:
char c;
std::cin >> c;
// what is the result type?
make_slit(c);
I should note however that during the design of literal string operators it was suggested that a function template form be allowed (much like they are for integer and floating-point literals), which would achieve 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 brought up most recently in 2013 with Richard Smith’s n3599: Literal operator templates for strings. Unfortunately I don’t know what the current status of the feature is.
You can find a solution to expand a string literal to a parameter pack 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 the constexpr strlen with a custom literal, it returns the length directly and remove the dependency with relaxed constexpr function of C++1y.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With