我有以下示例类 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说:
error:
constexpr Foo::Bar<T>::Bar() [with T = int]
used before its definitionconstexpr static auto b = Bar<int>{};
和Clang :
error: constexpr variable
b
must be initialized by a constant expressionconstexpr static auto b = Bar<int>{};
我不知道标准是否不允许这样做,但我的猜测是不知何故 b
是一个不完整的类型。
让事情变得更有趣的是,如果我删除 constexpr
,我可以让 GCC 和 Clang 正常运行。 ,或者如果我移动 Bar
的定义在Foo
之外.
以下哪个编译器是正确的?
请注意,此问题的灵感来自于以下内容:
- Simple constexpr LookUpTable in C++14 (我的问题是这个未回答问题的一部分)
- Nested struct breaks constexpr despite being identical to global ones (这似乎提供了一些关于正在发生的事情的见解)
最佳答案
来自 n4140
§ 9.2.2 [class.mem](强调我的)
A class is considered a completely-defined object type (3.9) (or complete type) at the closing
}
of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.
Clang 和 GCC 是正确的。当您声明您的 static constexpr
成员时,该类不被认为是完整的,因此您无法构造它。这就是为什么将 Bar
的定义移出或删除 static constexpr
的原因(因为在定义非静态成员时它被认为是完整的)
澄清一下,特别是考虑这个问题:Static constexpr member of an inner class
我上面引用的标准基本上意味着除非另有说明一个类在其自身内被认为是不完整的*。 static
、constexpr
或 static constexpr
初始化器不属于 otherwise specified 部分,因此我们可以不使用类中声明的任何,其中包括嵌套类类型。
*表示您不能在类声明中使用它或它的成员。最著名的异常(exception)是在成员函数中。
关于c++ - 静态模板化 constexpr 嵌套类成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45841822/