Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 静态模板化constexpr嵌套类成员_C++_Templates_C++14_Language Lawyer_Constexpr - Fatal编程技术网

C++ 静态模板化constexpr嵌套类成员

C++ 静态模板化constexpr嵌套类成员,c++,templates,c++14,language-lawyer,constexpr,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: cons

我有以下示例类
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();
    }
};
GCC和Clang都在这里抱怨,但MSVC没有

说:

错误:
constepr Foo::Bar::Bar()[带T=int]
在其定义之前使用

constexpr static auto b = Bar<int>{};
我不知道标准是否不允许这样做,但我的猜测是,不知何故,
b
是一种不完整的类型

更有趣的是,如果我删除
constexpr
,或者如果我将
Bar
的定义移到
Foo
之外,我就可以让GCC和Clang正常工作

以下哪种编译器是正确的? 请注意,这个问题的灵感来自以下方面:

  • (我的问题是这个未回答问题的一部分)
  • (这似乎提供了一些关于正在发生的事情的见解)
来自n4140

§9.2.2[类别mem](重点矿山)

类被视为完全定义的对象类型(3.9)(或 在类说明符的结束符
}
处输入完整类型)。在 类成员规范,则该类在 函数体、默认参数、使用声明 继承构造函数(12.9)、异常规范和 非静态数据成员的大括号或同等初始值设定项(包括 嵌套类中的此类内容)否则视为不完整 在其自己的类成员规范中

Clang和GCC是正确的。当您声明
static constexpr
成员时,该类被认为是不完整的,因此您无法构造它。这就是为什么将
Bar
的定义移出或删除
static constexpr
有效的原因(因为在定义非静态成员时它被认为是完整的)


为了澄清,特别是考虑到这个问题:

我上面引用的标准基本上意味着,除非另有规定,否则类本身被视为不完整*。
static
constexpr
static constexpr
初始值设定项不属于其他指定部分,因此我们不能使用类中声明的任何内容,其中包括嵌套类类型


*这意味着您不能在类声明中使用它或它的成员。最广为人知的例外是在成员函数中。

Bar
移动到
Foo
之外的事实向我表明,这里的一个因素是
Foo
的定义在类完全声明之前是不完整的。在
Foo
的定义结束之前,它的内部类不会被认为是完全定义的(这就是为什么内联clsas方法可以引用在它们之后声明的类成员)。
Bar
已经是一个,所以您不需要定义默认构造函数(在本例中)。如果你去掉了Bar的构造函数,就会发出叮当声和GCC。我知道这不能回答你的问题,但我认为值得一提。@SamVarshavchik我最初倾向于同意你的观点,只是简单地从
b
中删除
constepr static
就可以了。嗯。。。但我怎么能做到这一点:
constexpr static auto b=sizeof(Bar)答案的第二部分基本上说明了外部类型的不完整性也意味着嵌套类型的不完整性(即使后者“看起来”是完整的)。但是
sizeof
也需要一个完整的类型作为其参数。它怎么会用这种嵌套类型编译?@AnT:我更确信这里没有对标准进行详细说明。如果我默认使用嵌套类“
constexpr
constructor,那么它将工作。这样做是有意义的,因为编译器可以保证构造函数不会试图访问外部类的任何方面。否则,您可以引用外部类的
静态constexpr
成员,这会使事情复杂化。我说这个标准是“未指定的”,因为我认为基于它的编写方式,OP中的代码应该是格式良好的,但是实现者发现,如果允许的话,就不能做出真正的保证。@AnT:具体地说,我指的是嵌套类引用父类(legal)的
static constexpr
成员的地方,但是父类的
静态constexpr
成员是嵌套类的实例。一般来说,在最外层的类完成之前,编译器不能允许构造嵌套类(甚至
static constexpr
),除非它能保证某种循环引用不会发生(使用默认的ctor很容易保证)
constexpr static auto b = Bar<int>{};
constexpr static auto b = Bar<int>{};