我有以下示例类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>{};
错误:constexpr变量
初始化b
必须由常量表达式constexpr static auto b = Bar<int>{};
我无法判断标准是否禁止此,但我的猜测是b
不完整类型。
让事情变得更有趣的是,如果我移除constexpr
,或者我将Bar
的定义移到Foo
之外,我可以让GCC和Clang行事。
请注意,此问题的灵感来自以下内容:
答案 0 :(得分:3)
来自n4140
§9.2.2[class.mem](强调我的)
一个类被认为是一个完全定义的对象类型(3.9)(或 在类说明符的结束
中}
处完成类型。内 class member-specification ,该类被认为是完整的 函数体,默认参数,引用的使用声明 继承构造函数(12.9),异常规范和 brace-or-equal-initializers 用于非静态数据成员(包括 嵌套类中的这类东西)。 否则被视为不完整 在其自己的类 member-specification 。
Clang和GCC是正确的。当您声明static constexpr
成员时,该类不被视为完整,因此您无法构建它。这就是移动Bar
的定义或删除static constexpr
的原因(因为在定义非静态成员时 被认为是完整的)
澄清一下,特别是考虑这个问题:Static constexpr member of an inner class
我上面引用的标准基本上意味着除非另有说明一个类本身被认为是不完整的 * 。 static
,constexpr
或static constexpr
初始值设定项不属于指定的部分,因此我们无法使用任何内容在类中声明,包括嵌套的类类型。
*表示您不能在类声明中使用它或它的成员。最着名的例外是成员函数。