C++11 user-defined literals

822 views Asked by At

I'm learning C++11, and am interested in user-defined literals. So I decided to play a bit with it. Some languages have a syntax like this:

int n = 1000_000_000;

I tried to simulate this feature in C++11.

inline constexpr unsigned long long operator "" _000 (unsigned long long n)noexcept
{
      return n * 1000;
}

inline constexpr unsigned long long operator "" _000_000 (unsigned long long n)noexcept
{
      return n * 1000*1000;
}

inline constexpr unsigned long long operator "" _000_000_000 (unsigned long long n)noexcept
{
      return n * 1000*1000*1000;
}

int main(){
     constexpr auto i = 100_000; // instead of 100000
     constexpr auto j = 23_000_000; // instead of 23000000;
}

But for the general case I couldn't simulate it, i.e.

auto general_case = 123_456_789; //can't compile

My question is "Can I simulate for the general case as above using C++11?".

1

There are 1 answers

2
dtech On

This is not possible with user defined literals in the C++11 version of the language as it is right now. User defined literals support a limited format for parameters, doesn't seem to support a right side parameter, chaining, plus there is the problem of representing numbers that begin with 0 as actual numbers. So it is a no go.

You current approach defines _000 and so on as standalone literals, so the compiler will only work with them and no other. It is not like the _ is the operator and the 000 is some parameter you can work with unfortunately.

You could however use letter suffixes instead.

long long constexpr operator"" K (long double n) {
    return n * 1000;
}
long long constexpr operator"" M (long double n) {
    return n * 1000000;
}
long long constexpr operator"" G (long double n) {
    return n * 1000000000;
}

And then:

0.05M == 50000;
123.232K == 123232
1.000000001G == 1000000001

Surely, the last case sort of defeats the purpose, because once again you have many zeroes without visual indication... So you can go for something like:

1.G + 1 == 1000000001 // much clearer 1 billion + 1

This makes it a little ugly, since the literal expects a real number and won't work with an integer unless you define an extra literal just to use with integers. Then you can simply use 1G instead.

Also, this approach will likely produce compiler warnings, apparently the c++ group wants to reserve all suffixes that are not preceded by underscore for "future uses". If you want the warnings gone, just use _K _M and _G instead.

EDIT: I removed the initializer list solution, because it produces invalid results with numbers like 010, which is processed as octal and mess up the calculations.