#include <exception>
constexpr bool foo(bool x)
{
return x ? true : throw std::exception();
}
int main()
{
// 1) must never be compiled
// static_assert(foo(false), "");
// 2) must always be compiled?
const bool x = foo(false);
// 3) must never compile?
constexpr bool y = foo(false);
return 0;
}
I'm sure that (1) must lead to a compile error. I'm quite sure that (2) must not be rejected at compile time, though it will fail at runtime.
The interesting case is the constexpr variable (3). In this simple example, gcc and clang actually evaluate the expression, and will therefore reject the program. (Error message: y is not a constant expression).
Is every C++11 compiler forced to reject the program? What if foo(false) was replaced by a more complex expression?
I was suprised to find out that constexpr were not turing-complete, though it will be after a change in the specification: Is constexpr-based computation Turing complete?
Maybe this is related to my question. As far as I understand, the compiler is allowed to postpone the actual evaluation of the constexpr (3) in this example until runtime. But if constexpr are turing-complete, I find it hard to believe that the compiler can decide for all constexpr whether an exception will be thrown (which means that the constexpr is invalid).
A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.
constexpr functionsIts return type cannot be void , i.e., it must compute and return a value. It can only call other constexpr functions.
constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.
The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.
By my reading, yes, every compiler must complain about statement (3).
N3242 7.1.5 paragraph 9:
A
constexpr
specifier used in an object declaration declares the object asconst
. Such an object shall have literal type and shall be initialized. If it initialized by a constructor call, that call shall be a constant expression (5.19). Otherwise, every full-expression that appears in its initializer shall be a constant expression. Each implicit conversion used in converting the initializer expressions and each constructor call used for the initialization shall be one of those allowed in a constant expression (5.19).
I think of a constexpr
object as "evaluated at compile time", and a constexpr
function or constexpr
constructor as "might be evaluated at compile time". A compiler must determine the semantic validity of statements like (3) at compile time. You could argue that the "evaluation" can still be done at run time, but checking for validity does most of that work anyway. Plus, the code could then continue to instantiate a template like Check<y>
, which pretty much guarantees the compiler needs to figure out the value of y
at compile-time.
This does mean you could write a diabolical program to make the compiler take a really long or infinite time. But I suspect that was already possible with operator->
tricks.
I'm sure that (1) must lead to a compile error. I'm quite sure that (2) must not be rejected at compile time, though it will fail at runtime.
Correct. The throw
part of the conditional operator is not a constant expression, and in (1), it's not unevaluated. For (2), foo
is not forced to be evaluated at compile-time.
For (3), how would the compiler be allowed to post-pone evaluation? The constexpr
decl-specifier forces foo
to be evaluated at compile-time. It's basically the same as (1), initialization of y
is a context where a constant expression is required.
§7.1.6 [dcl.constexpr] p9
A
constexpr
specifier used in an object declaration declares the object asconst
. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.19). Otherwise, or if aconstexpr
specifier is used in a reference declaration, every full-expression that appears in its initializer shall be a constant expression. [...]
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