Constant integers and constant evaluation

Isn’t constant evaluation fun?

There are a few places in the language where we try to do constant evaluation and if that fails, we fallback to doing non-constant evaluation. Static initialization is one such place, initializing constant integers is another.

What happens with:

int const i = f();

is that this could be constant evaluation, but it doesn’t necessarily have to be. Because (non-constexpr) constant integers can still be used as constant expressions, if they meet all the other conditions, we have to try. For instance:

const int n = 42;       // const, not constexpr
std::array<int, n> arr; // n is a constant expression, this is ok

So try we do – we call f() as a constant expression. In this context, std::is_constant_evaluated() is true, so we hit the branch with the throw and end up failing. Can’t throw during constant evaluation, so our constant evaluation fails.

But then we fallback, and we try again – this time calling f() as a non-constant expression (i.e. std::is_constant_evaluated() is false). This path succeeds, giving us 1, so i is initialized with the value 1. But notably, i is not a constant expression at this point. A subsequent static_assert(i == 1) would be ill-formed because i‘s initializer was not a constant expression! Even though the non-constant initialization path happens to (otherwise) entirely satisfy the requirements of a constant expression.


Note that if we tried:

constexpr int i = f();

This would have failed because we cannot fallback to the non-constant initialization.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)