4

If I'm not mistaken, the arguments for a user defined literal are always known at compile time. In C++20 you can force functions to execute at compile time using consteval so that throw generates a compile time error.

#include <limits>

consteval int operator""_int(unsigned long long int v) {
    if (std::numeric_limits<int>::max() < v) {
        throw "out of range";
    }
    return static_cast<int>(v);
}

int main() {
    return 1'000'000'000'000_int;
}
$ g++ -std=c++20 main.cpp
main.cpp: In function ‘int main()’:
main.cpp:11:12:   in ‘constexpr’ expansion of ‘operator""_int(1000000000000)’
main.cpp:5:9: error: expression ‘<throw-expression>’ is not a constant expression
    5 |         throw "out of range";
      |         ^~~~~~~~~~~~~~~~~~~~

In my experience, compile-time errors are generally preferable to run-time errors.

If other functions have to be called in the definition that are not constexpr, then consteval is obviously not an option. But apart from this case, I can't think of any reason not to use consteval.

Is there any other reason not to mark user defined literals as consteval?

Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51

2 Answers2

5

User defined literals may return heap-allocated objects such as std::string, in which case consteval cannot be used because the function body is not a constant expression.

If the implementation itself can be used as a constant expression, there is no good reason not to use consteval.

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • 3
    C++20 also makes `std::string` usable at compile time. However, being `consteval` means that you cannot use the result at runtime, since compile-time allocations cannot leak into runtime code. So it's still a problem to presume that a string literal must be `consteval`. – Nicol Bolas Mar 25 '23 at 03:09
3

The only thing I can think of is that it would preclude you from doing (for example):

int i = 42;
auto x = operator""_int (i);

But that is rather artificial, and you might never foresee the need.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48