Suppose I have some class:
template <typename T>
class Foo {
const T* x_;
public:
Foo(const T* str) : x_{str} {}
};
and I provide some user-defined literals that create a Foo
object:
Foo<char> operator"" _foo(const char* str, std::size_t) {
return Foo<char>{str};
}
Foo<wchar_t> operator"" _foo(const wchar_t* str, std::size_t) {
return Foo<wchar_t>{str};
}
// etc. for char16_t and char32_t.
My question is this: why can I not template these and save having to rewrite code?
template <typename T>
Foo<T> operator"" _foo(const T* str, std::size_t) {
return Foo<T>{str};
}
gcc 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.4) and 7.0.0 (compiled myself) report:
error: ‘Foo<T> operator""_foo(const T*, std::size_t)’ has invalid argument list
Foo<T> operator"" _foo(const T* str, std::size_t) {
^
The error message seems to be clear enough, but I don't see a reason why I shouldn't be allowed to do this in principle; so, am I doing this incorrectly, or is this genuinely not allowed?
In source code, any literal, whether user-defined or not, is essentially a sequence of alphanumeric characters, such as 101 , or 54.7 , or "hello" or true . The compiler interprets the sequence as an integer, float, const char* string, and so on.
C++ Literals. Literals are data used for representing fixed values. They can be used directly in the code. For example: 1 , 2.5 , 'c' etc. Here, 1 , 2.5 and 'c' are literals.
A "string literal" is a sequence of characters from the source character set enclosed in double quotation marks (" "). String literals are used to represent a sequence of characters which, taken together, form a null-terminated string. You must always prefix wide-string literals with the letter L.
Consider this:
If the literal operator is a template, it must have an empty parameter list and can have only one template parameter, which must be a non-type template parameter pack with element type char
In other terms, the declaration of a literal operator template should be:
template <char...> double operator "" _x();
That is not your case.
I'm not a language-lawyer, but I guess the section of the standard that is relevant for your case is [over.literal] (link to the working draft).
An excerpt from [over.literal]/2 follows:
A function template declared with a literal-operator-id is a literal operator template.
Below [over.literal]/5 is quoted:
The declaration of a literal operator template shall have an empty parameter-declaration-clause and its template-parameter-list shall have a single template-parameter that is a non-type template parameter pack ([temp.variadic]) with element type char.
It seems to me that declarations similar to the one in the question are explicitly disallowed by the standard.
More in general, a function template that declares a literal operator must adhere strictly to the given pattern.
am I doing this incorrectly, or is this genuinely not allowed?
I would say that's genuinely not allowed.
Anyway, you can still use a template function if you have complex logic that you don't want to repeat in each operator:
template<typename T>
Foo<T> create(const T *str) {
// your logic...
return Foo<T>{str};
}
Foo<char> operator"" _foo(const char *str, std::size_t) {
return create(str);
}
Foo<wchar_t> operator"" _foo(const wchar_t *str, std::size_t) {
return create(str);
}
It's a matter of an extra layer of indirection and that's all.
Obviously, it doesn't worth it if all your operators are one line body functions.
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