template<const char* TS> struct t{};
int main()
{
t<"hi"> a{};
t<"hi"> b{};
}
// Issue: does `TS` have the same address for `a` and `b`?The problem seems to be that, since string literals really are pointers/references, there's no sensible way of dealing with them as compile-time template parameters.
But it would be really useful to have such a feature:
template<magic TS> struct tag{}; int main() { database::table<tag<"user">, database::field<tag<"name">, std::string>, database::field<tag<"age">, int> > db_user; db_user.get<tag<"name">>(id(10)); db_user.get<tag<"age">>(id(10)); }
Another example:
template <typename F, std::size_t ... I> constexpr auto string_builder(F f, std::index_sequence<I...>) { return char_sequence<f(I)...>{}; } template<magic TS> auto tag(TS s) { return string_builder([]() constexpr { return s; }, magic_sizeof(s)); } int main() { static_assert(is_same(decltype(tag("hi")), decltype(tag("hi")))); static_assert(!is_same(decltype(tag("hi")), decltype(tag("bye")))); }
The above examples show the definition of unique types based on strings in-situ without using macros. (It is already possible with macros.)
The problem is that there currently is nothing in the language that could be used as "magic".
magic should simply be a char... pack. char... packs as template parameters.template<typename> struct t_typename{}; template<const char*> struct t_constchar{}; template<const char(&)[3]> struct t_charref{}; template<char...> struct t_chars{}; template<auto> struct t_auto{}; template<auto...> struct t_autos{}; int main() { t_typename<"hi">{}; // still would FAIL to compile, as intended t_constchar<"hi">{}; // still would FAIL to compile, as intended t_charref<"hi">{}; // still would FAIL to compile, as intended t_chars<"hi">{}; // should COMPILE with the proposed changes t_auto<"hi">{}; // still would FAIL to compile, as intended t_autos<"hi">{}; // should COMPILE with the proposed changes }
Using char... instead of pointers/reference would make the literal behave just a sequence of compile-time characters.
What do you think?
The same problem is addressed by P0424R0, but only for user-defined literals.
I think that allowing string literals to be matched into template char... argument packs would make sense, because the programmer only cares about the literal's "characters" (not its address) at compile-time.
Let me just expand a bit on what Matt said.I think this is a brilliant idea, but I don't think it's going to work, for the same reasonas my P0424R0 paper was not warmly received. The reason is that implementersdon't want anything that encourages the use of large template parameter lists,because the representation of that inside the compiler is too inefficient. They don'twant a single template parameter per character in the string, because the structurethat represents a template parameter in the compiler is expensive. Instead, they'drather have a single structure that represents all the characters. I'm not sure why theycan't just represent a character pack in a more efficient manner, but that's what Iwas told when I presented in EWG.So on Saturday, we tried looking into passing arrays as template arguments, butthat becomes messy because arrays are already supported, but they decay topointers so we'd need to support a new syntax. We then tried passing std::array,but doing this cleanly would require passing arbitrary literal types as templatearguments, which is also non-trivial of a change.I have not started writing a paper yet, because I don't have any solution in mindat this time to be honest. However, this is one of the most valuable problems tobe solved for metaprogramming, so I'll take anything that works.
constexpr auto str = "Hello"lit;
static_assert(is_same<decltype(str), decltype("Hello"lit)>::value);
static_assert(is_same<decltype(str)::char_type, char>::value);
static_assert(s[0] == 'H');No, this has not been discussed AFAICT. That's not a bad idea, but it does seem very magic to me.I don't know whether it's more desirable to introduce this special case or to "fix" the problem byallowing user defined types with some restrictions as template arguments. Certainly the latter iscleaner, but also much more difficult.
static_assert(is_same<decltype("Hello"lit + " World"lit), decltype("Hello World"lit)>::value);
Sorry if I'm asking the obvious question here: Why not guarantee that different string literals have different addresses and the same string literal has the same address and use const char* as non-type template parameters?
Jonathan
What about automatically generating types for string-literals?Probably with a built-in literal operator 'lit' that does the compiler magic.
So on Saturday, we tried looking into passing arrays as template arguments, butthat becomes messy because arrays are already supported, but they decay topointers so we'd need to support a new syntax. We then tried passing std::array,but doing this cleanly would require passing arbitrary literal types as templatearguments, which is also non-trivial of a change.
How about allowing literal types as template arguments if they havedefaulted == and != operators (and this condition also applies recursivelyto all of their members). It does look fairly likely that we will get default ==in the language in the near future. Once we have that, it would providea natural way to express which types are unproblematic for use astemplate arguments.This would be more than good enough to get us arrays of characters.
Since f() is an inline function, the returned string literal is required
to have the same address in all TUs:
C++14 [dcl.fct.spec] Function specifiers p4:
...
A string literal in the body of an extern inline function is the same
object in different translation units.
...
Let me just expand a bit on what Matt said.I think this is a brilliant idea, but I don't think it's going to work, for the same reasonas my P0424R0 paper was not warmly received. The reason is that implementersdon't want anything that encourages the use of large template parameter lists,because the representation of that inside the compiler is too inefficient. They don'twant a single template parameter per character in the string, because the structurethat represents a template parameter in the compiler is expensive. Instead, they'drather have a single structure that represents all the characters. I'm not sure why theycan't just represent a character pack in a more efficient manner, but that's what Iwas told when I presented in EWG.