#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).
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 forcesfoo
to be evaluated at compile-time. It's basically the same as (1), initialization ofy
is a context where a constant expression is required.§7.1.6 [dcl.constexpr] p9
By my reading, yes, every compiler must complain about statement (3).
N3242 7.1.5 paragraph 9:
I think of a
constexpr
object as "evaluated at compile time", and aconstexpr
function orconstexpr
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 likeCheck<y>
, which pretty much guarantees the compiler needs to figure out the value ofy
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.