37

Consider:

struct str {};

str operator"" _X(long double d) {
    return str();
}

This compiles fine with g++ 4.7.2 Wall std=c++11

but now if I give a double :

str operator"" _X(double d) {
    return str();
}

I get the following error message: main.cpp|3|error: 'str operator"" _X(double)' has invalid argument list

What is the problem ? Has this something to do with "It is not possible to redefine the meaning of a built-in literal suffix" (Stroustrup FAQ) ? Can you think of a workaround ?

Bérenger
  • 2,678
  • 2
  • 21
  • 42

2 Answers2

51

What is the problem?

The problem is that the Standard forbids it. Per paragraph 13.5.8./3 of the C++11 Standard on user-defined literals:

The declaration of a literal operator shall have a parameter-declaration-clause equivalent to one of the following:

const char*
unsigned long long int
long double
char
wchar_t
char16_t
char32_t
const char*, std::size_t
const wchar_t*, std::size_t
const char16_t*, std::size_t
const char32_t*, std::size_t

Concerning a workaround, I am not sure it is needed, since the following works fine (a double gets implicitly converted to a long double, so you can pass in literals of type double):

struct str {};

str operator"" _X(long double d) {
    return str();
}

int main()
{
    str s = 4.0_X;
}
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • 5
    Ok thanks. But why ? I mean, was there something in the syntax that prevented to unable double ? – Bérenger May 16 '13 at 20:32
  • 7
    @BérengerBerthoul: Why would you use `double` when `long double` has as much or more range and precision? Probably for speed or memory usage reasons, right? Well, those aren't considerations for operations done at compile-time. If you want to perform operations with double precision, you can always use a cast inside the function. – Ben Voigt May 16 '13 at 20:34
  • @Ben Voigt Ok, fine for me. I just think it's a little bit of a kludge, but indeed there is no big pb. Thanks – Bérenger May 16 '13 at 20:39
  • 1
    @BérengerBerthoul It would be much more weird if you could use a `double` or even `float` as parameter and suddenly your literal wouldn't have the best precision possible in the implementation. The same for integers (which only have `unsigned long long`). How should a `1000000_x` behave, if you have `operator "" x(unsigned short)`? Probably not in the way the user of the literal expects it to behave. – Christian Rau May 17 '13 at 07:29
  • 3
    The standard would be a lot _less_ confusing if section 13.5.8/8 didn't contain `double operator""_Bq(double);` as an example of a valid operator... – Bo Persson Aug 25 '14 at 16:46
8

I think it's to prevent ambiguous overloads. What if you were allowed to define the following overload set

str operator"" _X(long double ld);
str operator"" _X(double d);
str operator"" _X(float f);

Can you give examples of user-defined literals in source code that would map to each of the above? No, there's no way to constrain the literal to a particular floating-point datatype.

What could be useful is this set:

str operator"" l_X(long double ld);
str operator""  _X(long double d);
str operator"" f_X(long double f);

Since now you could write

3.0_X  // treated like a double
3.0l_X // treated like a long double
3.0f_X // treated like a float
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • It's possible, but I don't think so. It will go against C++ philosophy to enable shooting yourself in the foot if at the same time you can get benefits. And indeed this would have benefits. For instance, in my real code, the struct "str" is template, and in particular instantiated for "double". And for that I can't use the "long double" trick (except with specialization, but this is really becoming kludgy, and e.g. partial specialization is not allowed for functions...) – Bérenger May 16 '13 at 21:19
  • 1
    @BérengerBerthoul: Feel free to write your operator as `str operator"" _X(long double ld) { double d = ld; /* use d */ }` – Ben Voigt May 16 '13 at 21:38