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.
constexprBy 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.
constevalI 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
constexprorconstevalfunction.
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