Using static_assert
to generate compile-time error is not always easy because it requires a constant expression as first argument. I found, on StackOverflow, several example where throw
was used instead of static_assert
:
static_assert(<constante evaluated condition>,"message");
if (<condition>) {throw "message";}
My question is, is it legal to do that inside constexpr
or consteval
function.
For instance, if I want to check at compile time if some integer is positive (pretty dumb...) I may write:
CONSTSPEC void checkpos(int x) {
if (x < 0) {
// is this ill-formed, no diagnostic required (when called with a
// negative argument?)
throw "argument must be positive";
}
}
LIVE
Where CONSTSPEC
can be constexpr
or consteval
.
constexpr
By looking at https://timsong-cpp.github.io/cppwp/n4861/dcl.constexpr#6 and also this answer it seems that calling checkpos
with a strictly negative argument is ill-formed but no diagnostic is required, letting a compiler do whatever he wants, which would be useless for compile-time error detection.
consteval
I can't find a word in the standard. Should I understand that then any call is well-formed and passing a strictly negative argument will result in a mandatory compile-time error?
Is throw
usable inside a constexpr
function (I don't think so) or inside a consteval
function (maybe) to generate a compile-time error?
My question is, is it legal to [throw exceptions] inside
constexpr
orconsteval
function.
Before C++26, this would make the surrounding constant expression not a constant expression, which would usually have the same effect as a failed static_assert
.
If you don't intend to catch the exception anyway, you can just throw
, goto
, or do something else that's not allowed in constant expressions.
People just use throw "message"
by convention, but x: goto x; // message
would have the same effect.
After P3068R6: Allowing exception throwing in constant-evaluation in C++26, you can also catch exceptions thrown at compile time. Considering that, it may be best to write:
throw std::invalid_argument("argument must be positive");
... which would work exactly as expected after C++26 and have a useful exception type, and behave like an "uncatchable exception" before that.
By looking at https://timsong-cpp.github.io/cppwp/n4861/dcl.constexpr#6 and also this answer it seems that calling checkpos with a strictly negative argument is ill-formed but no diagnostic is required, letting a compiler do whatever he wants, which would be useless for compile-time error detection.
No, you misunderstand that. The program would be ill-formed if you wrote a function like:
constexpr void f() { throw; }
The condition is that
no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression
... but in the case of checkpos
, you could call checkpos(0)
, and that would be a constant expression.
Whether you always call it with negative arguments or not doesn't matter.
You could call it with some arguments that would make it a constant expression.
For consteval
, the same rules would apply since both constexpr
and consteval
make a function a "constexpr function".
Note that these restrictions no longer exist in C++23 after P2448R2: Relaxing some constexpr
restrictions
The declaration of f()
above would be okay.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With