我遇到了似乎违反直觉的错误,即无法将constexpr
函数的值分配给constexpr
字面(希望我使用该语言)对)。这是一个例子:
class MyClass {
public:
static constexpr int FooValue(int n) { return n + 5; }
static constexpr int Foo5 = FooValue(5); // compiler error
static constexpr int Foo5Alt(void) { return FooValue(5); } // OK
};
在GCC 4.8.4中,Foo5
被标记为field initializer is not constant
。发现this thread表明旧版GCC可能是罪魁祸首。所以我将其插入Coliru(GCC 6.2.0)并收到错误'static constexpr int MyClass::FooValue(int)' called in a constant expression before its definition is complete
。我添加了Foo5Alt()
,它将其值作为constexpr
函数而不是文字返回,并且编译得很好。
我想我没有注意为什么FooValue(5)
无法用作Foo5
的初始值设定项。 FooValue(int n)
的定义已经完成,不是吗? { return n + 5; }
是整个定义。 constexpr
表示可以在编译时完全评估的表达式,那么为什么不能用它来定义constexpr
字面值的返回值?
我错过了C ++的微妙之处?
答案 0 :(得分:5)
在C ++中,只有在类的声明完成后才会解析类的成员函数的内联定义。
所以即使编译器“知道”了MyClass::FooValue(int)
,它还没有“看到”它的定义,因此它不能用在constexpr
表达式中。
一般的解决方法是坚持constexpr
成员函数,或在类外声明constexpr
常量。
答案 1 :(得分:4)
根据标准,当您尝试调用MyClass
初始化FooValue
时,Foo5
被视为不完整类型。因此,您不能像过去那样使用其成员
在结束}
时,该类型被视为完全定义的对象类型(或完整类型)。
另一方面,该类在函数体中被视为完整。这就是Foo5Alt
编译得很好的原因
有关详细信息,请参阅[class.mem]/6。