关于 constexpr 的疑问

2018-06-06 17:27:26 +08:00
 paparika

class TestClass1{ public:

static constexpr int getInt(){return 0;};

static constexpr int y = getInt();//why it's wrong?

TestClass1(){}

};

编译失败了,why?

2145 次点击
所在节点    C
16 条回复
enenaaa
2018-06-06 17:36:14 +08:00
constexpr 也要遵守基本法。c++类成员声明不接受赋值啊。
paparika
2018-06-06 17:43:54 +08:00
@enenaaa static constexpr int y = 0; 能过,这个算初始化不算赋值?
enenaaa
2018-06-06 17:46:22 +08:00
不好意思, 我忘了 static 变量是可以的
wens07
2018-06-06 17:48:03 +08:00
getInt 是一个 expresion,这样不行的吧
paparika
2018-06-06 17:48:50 +08:00
编译器报的 error: ‘ static constexpr int TestClass1::getInt()’ called in a constant expression
wwqgtxx
2018-06-06 17:49:08 +08:00
GCC 的提示说的挺清楚的了吧
error: 'static constexpr int TestClass1::getInt()' called in a constant expression before its definition is complete
wwqgtxx
2018-06-06 17:50:32 +08:00
也就是说这样写是可行的
class TestClass1{ public:

static constexpr int getInt(){return 0;};

TestClass1(){}
};

class TestClass2{ public:

static constexpr int y = TestClass1::getInt();//why it's wrong?

TestClass2(){}
};
paparika
2018-06-06 17:55:33 +08:00
@wwqgtxx 不太理解,信息给足了啊,怎么还不算 complete,有反例吗
wwqgtxx
2018-06-06 17:58:15 +08:00
@paparika 他的意思是只能在类的定义完成之后才能以 constexpr 的形式调用,至于为什么,你可能需要翻翻 C++的标准了
paparika
2018-06-06 18:00:21 +08:00
@wwqgtxx 暂时这么强行理解了,thx
vsomeone
2018-06-06 18:37:09 +08:00
https://stackoverflow.com/questions/11522399/constexpr-initializing-static-member-using-static-function:

The most likely reason for this is that constexpr variables have to be available as compile-time constant expressions from inside the bodies of member functions, so the variable initializers are completely defined before the function bodies -- which means the function is still incomplete (undefined) in the context of the initializer, and then this rule kicks in, making the expression not be a constant expression.

大致意思就是,由于 constexpr 必须是 compile-time known 的,所以它们的 initializer 定义位于它们所在的 function/class 之外。因此,你的代码等价于:

```c++

constexpr int TestClass1::y = initializer_for_y();

class TestClass1{ public:

static constexpr int getInt(){return 0;};
static constexpr int y;//why it's wrong?
TestClass1(){}
};
```

但是在 initializer_for_y() 试着调用 getInt() 的时候 TestClass1 尚未定义。这也就是为什么编译器会报告:
note: undefined function 'getInt' cannot be used in a constant expression
gnaggnoyil
2018-06-06 23:38:50 +08:00
@paparika 然而你现在只能这样强行理解……因为事实上标准中没有任何字句显式要求成员函数的类内定义一定不能在类的内部起效,而只是要求在类内部的时候类是一个不完全类型……换句话说标准没有要求你这种写法一定是错的.事实上你会发现在 Clang 和 GCC 下只要给 TestClass1 加一个模板参数编译错误就嗷的一声不见了…… https://wandbox.org/permlink/MiclIS7tSl4qR91C

我搜了一下发现 CWG1626( http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1626)提到了这个问题,然而很明显 WG21 至今仍在无视这个 2013 年就提出来的 CWG...
gnaggnoyil
2018-06-06 23:44:11 +08:00
@gnaggnoyil 干……发错.演示地址是这个: https://wandbox.org/permlink/hDmeC12PUHPRmoPp
paparika
2018-06-07 09:16:17 +08:00
@vsomeone
@gnaggnoyil

厉害厉害!
alqaz
2018-06-08 17:30:31 +08:00
@gnaggnoyil 是不是可以理解成编译器处理模板在处理 constexpr 之前,加了模板参数之后,先扫描一边 TestClass1,此时编译器对 TestClass1::getInt() constexpr 函数已经知道了。然后处理 constper 相关的计算也就可以了。
gnaggnoyil
2018-06-08 17:49:36 +08:00
没仔细读 GCC 和 Clang 的源码.不过它们都是支持 two-phase lookup 的而你理解的这种行为按照 two-phase lookup 的要求是 ill-formed,虽然没要求有 diagnostics...

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/460939

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX