静态模板化constexpr嵌套类成员

时间:2016-09-08 01:01:36

标签: c++ templates c++14 language-lawyer constexpr

我有以下示例类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行事。

这些编译器中的哪一个是正确的?

请注意,此问题的灵感来自以下内容:

1 个答案:

答案 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

我上面引用的标准基本上意味着除非另有说明一个类本身被认为是不完整的 * staticconstexprstatic constexpr初始值设定项不属于指定的部分,因此我们无法使用任何内容在类中声明,包括嵌套的类类型。

*表示您不能在类声明中使用它或它的成员。最着名的例外是成员函数。