【发布时间】:2015-05-25 11:33:58
【问题描述】:
来自<cassert> 的assert 宏提供了一种确保满足条件的简洁方法。如果参数的计算结果为true,则它不会产生任何进一步的影响。但是,在这种情况下,它的调用是否也可以在常量表达式中使用?
【问题讨论】:
-
当前活跃gcc bug
标签: c++ language-lawyer c++14 assert constant-expression
来自<cassert> 的assert 宏提供了一种确保满足条件的简洁方法。如果参数的计算结果为true,则它不会产生任何进一步的影响。但是,在这种情况下,它的调用是否也可以在常量表达式中使用?
【问题讨论】:
标签: c++ language-lawyer c++14 assert constant-expression
这是由LWG 2234 处理的,在引入了对constexpr 函数的放宽约束后,该问题重新引起了人们的注意。
建议的决议:
此措辞与 N3936 相关。
在 17.3 中的现有列表中引入以下新定义 [定义]:
常量子表达式 [defns.const.subexpr]
作为 条件表达式 CE (5.16 [expr.cond]) 的子表达式的表达式不会阻止 CE 成为核心常量表达式 (5.20 [ expr.const])。
在 19.3 [assertions] p1 之后插入一个新段落,如下所示:
-?- 表达式
assert(E)是一个常量子表达式 ([defns.const.subexpr]),如果有的话
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);
}
【讨论】:
e 的子表达式可以是 e 本身,不是吗? (例如比较 §1.9/10)或者您实际上是指 CS 根本不是 CE 的一部分?
<= 而不是比<)——这是我想要解决的第二点。第一点是函数中的语句不是函数调用表达式的子表达式。 -- 哦,毛巾日快乐;)
f() 的子表达式,而不会出现在其中。
f 中的表达式是该段落中f() 的子表达式:它谈到了表达式的求值 ,这并不是说这些成为/是f() 的一部分。