c++c++20constant-expressionuser-defined-literalsconsteval

Should user defined literals always be consteval in C++20?


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?


Solution

  • 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.