断言是否可用于常量表达式?

Col*_*mbo 12 c++ assert language-lawyer constant-expression c++14

assert从-macro <cassert>提供了保证条件满足一个简洁的方式.如果参数的计算结果为true,则不会产生任何进一步的影响.但是,在这种情况下,它的调用是否也可以在常量表达式中使用?

Col*_*mbo 9

这是由LWG 2234处理的,constexpr在引入了对功能的轻松限制后,它又引起了关注.

拟议决议:

这个措辞与N3936有关.

  1. 在17.3 [定义]中将以下新定义引入现有列表:

    量子表达式 [defns.const.subexpr]

    一个表达式,其作为条件表达式CE(5.16 [expr.cond])的子表达式的评估 不会阻止CE成为核心常量表达式(5.20 [expr.const]).

  2. 按照指示在19.3 [断言] p1之后插入一个新段落:

    - ? - 表达式assert(E)是一个常量子表达式([defns.const.subexpr]),如果有的话

    • NDEBUG 定义在断言(E)出现的点,或

    • E上下文转换为bool(4 [conv]),是一个常量子表达式,其值为true.

常表子表达式

这个解决方案引入了一个常量子表达式的概念- 本质上是一个表达式,它本身不是(必然)一个常量表达式,但可以在一个表达式中使用.例如,考虑一下

constexpr void f() {
    int i = 0;
    ++i;
}
Run Code Online (Sandbox Code Playgroud)

++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);
Run Code Online (Sandbox Code Playgroud)

b是一个常量子表达式并true在调用中求值check(true),因此assert(b)是一个常量子表达式,因此不会阻止check(true)它成为一个子表达式.

当然,与static_assert模板相同的陷阱也是可能的.鉴于NDEBUG未定义,此定义格式不正确,§7.1.5/ 5无需诊断:

constexpr void fail() {
    assert(false);
}
Run Code Online (Sandbox Code Playgroud)