assert 可用于常量表达式吗?

Is assert usable in constant expressions?

来自 <cassert>assert 宏提供了一种确保满足条件的简洁方法。如果参数的计算结果为 true,则它不会产生任何进一步的影响。但是,在那种情况下,它的调用也可以在常量表达式中使用吗?

这已由 LWG 2234 处理,在引入对 constexpr 函数的宽松限制后重新引起注意。

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.

常量子表达式

该决议引入了 常量子表达式 的概念 - 本质上是一种表达式,它本身(不一定)是常量表达式,但可以在其中使用。考虑例如

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

++i 不是常量表达式,因为它修改的对象的生命周期开始于该表达式之外 (§5.20/(2.15))。然而,表达式 f() 完全是一个常量表达式,因为前一点不适用 - i 的生命周期从 f 开始。因此 ++i 是常量子表达式,因为 ++i 不会阻止 f() 成为常量表达式。

assert?

决议的第二部分保证 assert(E) 是常量子表达式,如果定义了 NDEBUG 或参数本身是常量子表达式,计算结果为 true。这意味着对 assert 的调用也可以是标准常量表达式。

以下是合式的:

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

b 是常量子表达式,在调用 check(true) 时计算结果为 true,因此 assert(b) 是常量子表达式,因此不会阻止 check(true) 从成为一个。

当然,与模板中 static_assert 相同的陷阱是可能的。鉴于 NDEBUG 未定义,此定义格式错误,§7.1.5/5 不需要诊断:

constexpr void fail() {
    assert(false);
}