Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is assert usable in constant expressions?

The assert-macro from <cassert> provides a concise way of ensuring that a condition is met. If the argument evaluates to true, it shall not have any further effects. However, can its invocation also be used inside a constant expression in that case?

like image 203
Columbo Avatar asked May 25 '15 11:05

Columbo


1 Answers

This was dealt with by LWG 2234, which was brought back to attention after relaxed constraints on constexpr functions had been introduced.

Proposed resolution:

This wording is relative to N3936.

  1. Introduce the following new definition to the existing list in 17.3 [definitions]:

    constant subexpression [defns.const.subexpr]

    an expression whose evaluation as subexpression of a conditional-expression CE (5.16 [expr.cond]) would not prevent CE from being a core constant expression (5.20 [expr.const]).

  2. Insert a new paragraph following 19.3 [assertions] p1 as indicated:

    -?- An expression assert(E) is a constant subexpression ( [defns.const.subexpr]), if either

    • NDEBUG is defined at the point where assert(E) appears, or

    • E contextually converted to bool (4 [conv]), is a constant subexpression that evaluates to the value true.

Constant subexpressions

This resolution introduced the notion of a constant subexpression - essentially an expression that is not (necessarily) a constant expression in itself, but can be used inside one. Consider for example

constexpr void f() {
    int i = 0;
    ++i;
}

++i is not a constant expression as it modifies an object whose lifetime started outside that expression (§5.20/(2.15)). However, the expression f() is in its entirety a constant expression, because the previous point does not apply - i's lifetime starts in f. Hence ++i is a constant subexpression, as ++i does not prevent f() from being a constant expression.

And assert?

The second part of the resolution guarantees that assert(E) is a constant subexpression if either NDEBUG is defined or the argument is itself a constant subexpression and evaluates to true. This implies that a call to assert can also be a bog-standard constant expression.

The following is well-formed:

constexpr int check(bool b) {
    assert(b);
    return 7;
}
constexpr int k = check(true);

b is a constant subexpression and evaluates to true in the call check(true), hence assert(b) is a constant subexpression and therefore does not prevent check(true) from being one.

Of course, the same pitfall as with static_assert in templates is possible. Given that NDEBUG isn't defined, this definition is ill-formed, no diagnostic required by §7.1.5/5 :

constexpr void fail() {
    assert(false);
}
like image 170
Columbo Avatar answered Nov 18 '22 01:11

Columbo