c ++ - 使用非静态数据成员和嵌套类构造的类内初始化时出错

以下代码非常简单,我希望它应该编译好。

struct A
{
    struct B
    {
        int i = 0;
    };

    B b;

    A(const B& _b = B())
        : b(_b)
    {}
};

我用g ++版本4.7.2,4.8.1,clang ++ 3.2和3.3测试了这段代码。 除了g ++ 4.7.2对此代码的段错误([http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57770),其他经过测试的编译器提供的错误消息并不能解释太多。

g ++ 4.8.1:

test.cpp: In constructor ‘constexpr A::B::B()’:
test.cpp:3:12: error: constructor required before non-static data member for ‘A::B::i’ has been parsed
     struct B
            ^
test.cpp: At global scope:
test.cpp:11:23: note: synthesized method ‘constexpr A::B::B()’ first required here 
     A(const B& _b = B())
                       ^

clang ++ 3.2和3.3:

test.cpp:11:21: error: defaulted default constructor of 'B' cannot be used by non-static data member initializer which appears before end of class definition
    A(const B& _b = B())
                    ^

使这些代码可编辑是可能的,似乎它应该没有区别。 有两种选择:

struct B
{
    int i = 0;
    B(){} // using B()=default; works only for clang++
};

要么

struct B
{
    int i;
    B() : i(0) {} // classic c++98 initialization
};

这段代码真的不正确还是编译器错了?

etam1024 asked 2019-09-11T00:34:49Z
2个解决方案
80 votes

这段代码真的不正确还是编译器错了?

嗯,都不是。 该标准有一个缺陷 - 它表示在解析B::B()的初始化程序时B被认为是完整的,并且A()(使用初始化程序A())可以在B::B()的定义中使用。这显然是循环的。 考虑一下:

struct A {
  struct B {
    int i = (A(), 0);
  };
  A() noexcept(!noexcept(B()));
};

这有一个矛盾:B隐含B::B() iff A()不抛出,A()不抛出iff B::B()不是noexcept.这个领域还有其他一些周期和矛盾。

这由核心问题1360和1397跟踪。特别注意核心问题1397中的这个注释:

解决这个问题的最好方法可能是使非静态数据成员初始化程序使用其类的默认构造函数。

这是我在Clang中实现以解决此问题的规则的特例。 Clang的规则是,在解析该类的非静态数据成员初始值设定项之前,不能使用类的默认默认构造函数。 因此,Clang在这里发布诊断:

    A(const B& _b = B())
                    ^

...因为Clang在解析默认初始值设定项之前解析默认参数,并且此默认参数需要B的默认初始值设定项已经被解析(为了隐式定义B::B())。

Richard Smith answered 2019-09-11T00:35:41Z
0 votes

也许这就是问题所在:

§12.15。默认构造函数是默认的,默认构造函数是默认构造函数,默认情况下是默认构造函数。   使用(3.2)创建其类类型(1.8)的对象,或者在第一次声明后显式默认的对象

因此,首次查找时会生成默认构造函数,但查找将失败,因为A未完全定义,因此无法找到A中的B。

fscan answered 2019-09-11T00:36:19Z
translate from https://stackoverflow.com:/questions/17430377/error-when-using-in-class-initialization-of-non-static-data-member-and-nested-cl