I found in user defined string literal the following:
- For user-defined string literals, let str be the literal without ud-suffix:
a) If the overload set includes a string literal operator template with a non-type template parameter for which str is a well-formed template argument, then the user-defined literal expression is treated as a function call
operator "" X<str>()
,
That sounds a bit mysterious to me. Can some one give an example how this can be used?
The following did not work at all and I can't catch the point what the non type template parameter for MyType
can be. It seems not a char* nor const char*:
template < ??? >
struct MyType
{
const char* c;
constexpr MyType( const char* in ): c{in}{}
};
template < MyType t > auto operator ""_y() { return t; }
int main()
{
"Check it"_y;
}
This is confusing wording, which was copied directly from the standard:
The confusing bit is the question of what "for which
str
is a well-formed template argument" specifically applies to. A direct reading of the passage from the standard suggests that "for which" refers to the "non-type template parameter", since that is the text directly preceding the words "for which". However, if you look at how the standard says the function will be invoked, you see this:str
is being passed to the operator, which the implication being that an implicit conversion will take place betweenstr
and the "non-type template parameter". That is,str
is a valid "template argument" of the overloaded function, not of the template parameter of the overloaded function. And thus, the "for which" part should refer to the "literal operator template with a non-type template parameter", not the "non-type template parameter".That having been said, to make your code work, you need to do more than to just remove the template argument from
MyType
.You might have noticed a certain oddity in C++ surrounding non-type template parameters (NTTP). For example, NTTPs have always been able to be pointers to things. But you could never do this:
The standard expressly forbids a pointer NTTP from being initialized with a string literal. And C++20 does not change this.
Therefore, you can't take a pointer. You have to take what the literal actually is: an array. But you can't make your code work by taking
const char (&in)[]
as a parameter either. A literal is not an unsized array (since an "unsized array" is not a real object type). That array parameter must be sized appropriately to the literal.Which means that you must deduce the size from a size template parameter.
Also, other rules flat-out forbid you from ever storing a pointer to a string literal in an NTTP (directly or indirectly). So, if you want a type that represents an entire string literal in an NTTP, that NTTP type must contain an array that is sized to that size.
So the simplest, functional string literal NTTP you could build would be:
And thanks to CTAD, you can just use
template < string_literal t > auto operator ""_y()
to define your UDL.Note that this
string_literal
class explicitly includes the NUL terminator as part of the array.