【发布时间】:2017-01-15 19:18:15
【问题描述】:
我有以下示例类Foo 和嵌套类Bar,一切都是constexpr:
class Foo
{
private:
template <typename T>
struct Bar
{
constexpr Bar(){}
constexpr int DoTheThing() const
{
return 1;
}
};
public:
constexpr static auto b = Bar<int>{};
constexpr Foo() {}
constexpr int DoTheThing() const
{
return b.DoTheThing();
}
};
而且我想测试调用Foo::DoTheThing 返回1:
int main()
{
constexpr Foo f;
static_assert(f.DoTheThing() == 1, "DoTheThing() should return 1");
}
GCC 和 Clang 都在这里抱怨,但 MSVC 没有
GCC 说:
错误:
constexpr Foo::Bar<T>::Bar() [with T = int]在其定义之前使用constexpr static auto b = Bar<int>{};
还有Clang:
错误:constexpr 变量
b必须由常量表达式初始化constexpr static auto b = Bar<int>{};
我无法判断标准是否不允许这样做,但我的猜测是 b 不知何故是一个不完整的类型。
让事情变得更有趣的是,如果我删除 constexpr,或者如果我将 Bar 的定义移到 Foo 之外,我可以让 GCC 和 Clang 正常运行。
哪些编译器是正确的?
请注意,此问题的灵感来自以下内容:
- Simple constexpr LookUpTable in C++14(我的问题是这个未回答问题的一部分)
- Nested struct breaks constexpr despite being identical to global ones(这似乎提供了一些关于正在发生的事情的见解)
【问题讨论】:
-
将
Bar移到Foo之外的事实向我表明,这里的一个因素是Foo的定义在类被完全声明之前是不完整的。直到Foo的定义结束,它的内部类才被认为是完全定义的(这就是为什么内联 clsas 方法可以引用在它们之后声明的类成员)。 -
Bar已经是literal type,因此您无需定义默认构造函数(在此示例中)。 Clang 和 GCC compile fine 如果您取出 Bar 的构造函数。我知道这不能回答你的问题,但我认为值得一提。 -
@SamVarshavchik 我最初倾向于同意你的观点,只是简单地从
b中删除constexpr static允许everything to work just fine。
标签: c++ templates c++14 language-lawyer constexpr