2017-07-27 67 views
1
int d = 1; 
constexpr void add() 
{ 
    d++; 
} 

int main() 
{ 

} 

GCC 7.1将在下面报告错误。错误信息非常清楚。问题是我在constexpr中没有看到任何明确的解释来描述它是非法的。为什么在constexpr非成员函数中访问全局非常量变量是不合法的

有人可以解释规范中定义的规则这种情况下违反吗?

 

main.cpp: In function 'constexpr void add()': 

main.cpp:8:1: error: the value of 'd' is not usable in a constant expression 

} 

^ 

main.cpp:4:5: note: 'int d' is not const 

int d = 1; 

    ^
+5

“至少存在一组参数值使得函数的调用可能是核心常量表达式的一个被评估的子表达式“ –

+0

似乎违反规则#16(对象的修改,除非对象具有非易失性字面量类型并且其生命周期开始于表达式的评估内)。但是如果我改为无效的add() d = 2; }然后它可以通过。 – Kane

+0

来自clang的错误消息看起来很清楚,常量表达式无法修改在该表达式之外可见的对象。但我仍然无法找到它在哪些规则中破解http://en.cppreference.com/w/cpp/language/constant_expression#Core_constant_expressions – Kane

回答

0

从引用你的标准角度来看,这些评论是很好的,但在这里希望有一个更直观的解释。

A constexpr函数在编译时必须可缩减为常量表达式。由于您正在与该函数中的常规,非constint进行交互,因此编译器无法确定d++在任何情况下都是如此。考虑以下情况:

int d; 
constexpr void add() { 
    d++; 
} 

void foo() { 
    int n; 
    std::cin >> n; 
    d = n; 
    add(); 
} 

在这种情况下,dfoo()值是在编译时不确定的,因此,不能确定你希望add()离开你的常量表达式。我希望有所帮助。

+0

这是不正确的。 constexpr只是意味着如果所有的前提条件都满足了,它将在编译时进行评估。否则,它会动态运行。 – Kane

2

cppreference

核心常量表达式是不具有任何的子表达式的下列中的任一个的任何表达式(忽略不计算表达式如的sizeof操作数或内置& &的右操作数当左操作数评估为false时)。

...

16)的对象的变形例中,除非该对象具有非易失性文字的类型和它的寿命开始的表达式的求值之内。

在你的榜样,d的一生开始add评价前 - 所以里面addd任何修改是非法的。引用上的示例专门用于递增,但这适用于所有修改。

编辑:不是从标准报价,因为据我所知,你得买它......

+0

我认为这个人的一生可能是理性的,但GCC7.1在这种情况下不会抱怨,http://coliru.stacked-crooked.com/a/d4e544c05b187b03。如果d = 2更改为d + = 2,则会发出抱怨。而且,相同的代码在叮当时总是失败,http://coliru.stacked-crooked.com/a/5d83921f7f0e871b – Kane

相关问题