10
votes

The new user-defined literal concept in C++ suggests some very interesting uses of string-literals, such as:

"Goodbye %s world"_fmt("cruel");
"Goodbye %s world"_fmt(123); // Error: arg 1 must be convertible to const char*

R"(point = \((\d+), (\d+)\))"_re; // Builds DFA at compile-time.

typedef table<
    column<"CustId"_name   , std::string>,
    column<"FirstName"_name, std::string>,
    column<"LastName"_name , std::string>,
    column<"DOB"_name      , date       >
> Customer;

However, when I build these kinds of constructs in gcc, e.g.:

template <char... Chars> Name<Chars...> operator "" _name() {
    return Name<Chars...>();
}

auto a = 123_name;    // OK
auto b = "abc"_name;  // Error

I get the following error:

…unable to find string literal operator ‘operator"" _name’ with ‘const char [4]’, ‘long unsigned int’ arguments

From reading around, I'm guessing that the variadic-template form is not available to UDLs derived from string literals.

  1. Is it in fact the case that string literals cannot be resolved using the variadic template form?
  2. If so, does anyone have any insight into why such a useful form of UDL was left out of the standard?
2
What exactly is useful about creating a new type for every literal, types that would be entirely distinct from one-another? - Nicol Bolas
@NicolBolas: In the examples shown, you want different literals to have different types. Moreover, the final type of a literal wouldn't necessarily be a naïve concatenation of its characters. For instance, "freq: %g Hz" world"_fmt(44000) might resolve to something like Formatter<double>("freq: ", " Hz")(44000) by means of metaprogramming. - Marcelo Cantos
That would also mean that you cannot pass it something that isn't a number. So you couldn't pass it something that it might use operator<< to convert into a stream, thus removing the possibility of customizing data types. - Nicol Bolas
Nice examples of usage of user-defined literals. - Diego Sevilla
@NicolBolas: If you mean that the %g is too constraining, that's easily solvable: "value(%<)"_fmt(t) could resolve to something like format("value(", stream_format(t), ")"), which would in turn invoke Formatter<StreamFormat<T>>("value(", ")")(t). - Marcelo Cantos

2 Answers

8
votes

You are right. String literals cannot be used with the variadic template form (§2.14.8/5):

If L is a user-defined-string-literal, let str be the literal without its ud-suffix and let len be the number of code units in str (i.e., its length excluding the terminating null character). The literal L is treated as a call of the form

operator "" X (str, len)

I have shuffled through the proposal papers (the latest of which I could find was N2750) and could not find an explanation for not allowing the use of the variadic template form.

2
votes

N3599, which allows this, has been implemented in gcc and clang.

template<class CharT, CharT... chars>
int operator ""_suffix(){
    return 42;
}