Jam*_*ree 7 c++ gcc language-lawyer constexpr c++11
例:
int main(int argc, char**)
{
constexpr int a = argc * 0;
(void)a;
constexpr int b = argc - argc;
(void)b;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
argc不是常量表达式,但编译器仍能够在两种情况下计算结果a和b编译时间(即0).
标准是否允许编译器与g ++一样聪明constexpr?
既不是argc * 0也不argc - argc是常量表达式,在某些情况下允许左值到右值的转换,这些都不适用于此.如果我们查看草案C++ 11标准部分5.19[expr.const],它会列出异常.它说:
条件表达式是核心常量表达式,除非它涉及以下之一作为潜在评估的子表达式[...]
并且有几个子弹,包括以下关于左值到右值的转换:
除非适用,否则左值到右值的转换(4.1)
一个整数或枚举类型的glvalue,它引用一个带有前面初始化的非易失性const对象,用一个常量表达式初始化,或者
一个文字类型的glvalue,它指的是用constexpr定义的非易失性对象,或者指的是这样一个对象的子对象,或者
一个文字类型的glvalue,它引用一个生命周期尚未结束的非易失性临时对象,用一个常量表达式初始化;
有趣的是,gcc不接受以下代码(现场直播):
constexpr int a = argc * 2;
Run Code Online (Sandbox Code Playgroud)
所以看起来gcc说我知道结果将为零,因此它执行常量折叠,并且不需要执行左值到右值的转换argc来确定结果.
不幸的是,我没有在章节5.19中看到任何允许这种短路的规定.这看起来非常类似于int a = 1中的情况,是一个|| 1一个常数表达式?有一个错误报告,但gcc团队中没有人回复那个.我在该错误报告中添加了评论,表明这似乎与此相关.
马克的评论如下表明这是一个错误:
有一个完整的c ++ - 延迟折叠分支,一些gcc开发人员正在使用它,这将延迟一些优化并可能解决这个问题.其他原因很重要,拒绝此问题中的代码的优先级非常低
常量表达式是否严格要求每个子表达式都是常量表达式?不,例如5.19它说:( 强调我的)
条件表达式是核心常量表达式,除非它涉及以下之一作为潜在评估的子表达式(3.2),但是未评估的逻辑AND(5.14),逻辑OR(5.15)和条件(5.16)操作的子表达式不被视为 [...]
所以以下是一个常量表达式:
constexpr int a = false && argc * 0;
Run Code Online (Sandbox Code Playgroud)
因为argc * 0评估&&从左到右和短路,所以不进行评估.