According to my (draft) version of C++17 (16.5.8 [over.literal]) as well as as cppreference.com, C++17 should have support for templated operators for user-defined string literals.
Specifically:
template <char...>
double operator "" _pi() {
return 0.;
}
int main() {
"test"_pi;
}
However, both gcc and clang yell at me:
// gcc -Wall -Wextra -pedantic -std=c++17
error: no matching function for call to 'operator""_pi<char, 't', 'e', 's', 't'>()'
7 | "test"_pi;
| ^~~~~~~~~
note: candidate: 'template<char ...<anonymous> > double operator""_pi()'
2 | double operator "" _pi() {
// clang -Wall -Wextra -pedantic -std=c++17
error: no matching literal operator for call to 'operator""_pi' with arguments of types 'const char *' and 'unsigned long', and no matching literal operator template
They both seem to want to nudge me towards the following template, which used be briefly considered to be part of C++17, but to my understanding did not become part of it:
template <typename T, T...>
double operator "" _pi() {
return 0.;
}
However, both gcc and clang correctly warn that this is a non-standard extension but they compile it correctly. Both gcc and clang claim to have full support of the C++17 core language.
What am I doing wrong? Is my draft AND cppreference.com inaccurate? I currently don't have access to the final standard version.
Use case
My use case is to implement the following, which is why I need the compile time information.
template <char... cs>
constexpr auto operator "" _a() {
return std::array<char, sizeof...(cs)>({cs...});
}
// "Hello"_a creates a std::array<char,5>
Best Answer
The template
char...
user defined literal is not for strings. It is called a numeric literal operator template and it allows you to have a literal operator that will take the number you are using and expand it into a pack for the template operator. For example, you would use your operator likeand that would resolve to calling
What you'd like to have is not possible in stock C++17
To get this to work, you'll need to upgrade to C++20, which lets you use a user defined type that can be constructed from a string literal, and use that to build the
std::array
. This is what is now called a string literal operator template. That would look likeand then
and that will resolve to a
std::array<char, 5>
. If you don't want the null terminator in the array, You just need to subtract1
fromN
everywhere it is used except for thechar const(&arr)[N]
parts.If you can't use C++20, you could switch this over to a couple of functions like
and then you would use it like