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