2

Suppose I want to define an integer literal which also allows for negative values, e.g. -12_km.

I.e., I would like to do

using coord_t = long long;
coord_t operator "" _km(long long int);

However, this is not accepted by my compiler (gcc).

The standard mentions a list of the allowed types for the parameter list of such a literal operator, but no signed integer type is among them.

Why is the standard like that? Why doesn't it allow for user-defined signed integer literals?

Tim Kuipers
  • 1,705
  • 2
  • 16
  • 26

2 Answers2

3

Because there are no negative integer literals in the grammar. Let's put aside the user-defined nature of your question. When we write -12, it's the literal 12, which has unary - applied to it. The grammatical definition of an integer literal contains no mention of a minus sign.

[lex.icon] (redacted and edited)

integer-literal:
    decimal-literal integer-suffix

decimal-literal:
    nonzero-digit
    decimal-literal digit

nonzero-digit: one of
    1  2  3  4  5  6  7  8  9

digit: one of 
    0 1 2 3 4 5 6 7 8 9

It's right there in the grammar. There are no productions that produce negative integer literal. And that is why user-defined literals follow the same convention. Their grammar production simply reuses the production for an integer literal

[lex.ext]

user-defined-literal:
    user-defined-integer-literal

user-defined-integer-literal:
    decimal-literal ud-suffix

Since negation is always an expression other than a literal, you need to overload the appropriate operator for coord_t. And by the way, the same applies for +12. It's a unary plus applied to 12, not a literal by itself.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
2

Because there are no negative integer literals in C++. -12 is actually the minus operator applying to the positive literal 12. That's the very reason why

So you need to overload the unary minus operator to use -12_km

coord_t operator "" _km(unsigned long long);
coord_t operator-();
phuclv
  • 37,963
  • 15
  • 156
  • 475
  • I've got `using coord_t = long long;` and the compiler gives errors when I try to define the unary minus `operator` in that way. Is there any way around that? – Tim Kuipers Nov 09 '20 at 17:02
  • @TimKuipers why do you overload without declaring a class? `coord_t` needs to be a struct or class. And you should also change the name because names ending with `_t` are reserved in POSIX: [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/q/228783/995714), [Does the ISO 9899 standard has reserved any use of the _t suffix for identifiers?](https://stackoverflow.com/q/56935852/995714). In fact `coord_t` is also a common name so you'll have a high chance of name clashing – phuclv Nov 10 '20 at 01:46
  • there's also [Boost.Units](https://www.boost.org/doc/libs/1_74_0/doc/html/boost_units.html) that you can use if possible to avoid redefining unist yourself – phuclv Nov 10 '20 at 01:51
  • thanks for the `_t` info. `coord_t` is not a class or struct, it's a typename for the primitive type `long long`. – Tim Kuipers Nov 11 '20 at 17:09
  • In the mean time I've found out that I don't need to overload the unary minus operator at all. – Tim Kuipers Nov 11 '20 at 17:09
  • 1
    @TimKuipers it's because your `coord_t` is just an alias of `long long` – phuclv Nov 12 '20 at 01:29