在常量表达式中可用的断言

Is assert usable in constant expressions?

本文关键字:断言 常量 表达式      更新时间:2023-10-16

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

这是由LWG 2234处理的,在constexpr函数的宽松约束引入后又引起了人们的注意。

提出决议:

此措辞与N3936有关。

  1. 在17.3中向现有列表引入以下新定义【定义】:

    constant subexpression [definitions . consts . subbexpr]

    作为条件表达式CE (5.16 [expr.cond])的子表达式的求值不会阻止CE作为核心常量表达式(5.20 [expr.const])。

  2. 在19.3[断言]p1后面插入新的段落:

    - ?-表达式assert( E )是一个常量子表达式([defns. consts . subbexpr]),如果

    • NDEBUG定义在assert(E)出现的地方,或者

    • E上下文转换为bool (4 [conv]),是一个常量子表达式,计算结果为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);
}