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

eta*_*024 88 c++ language-lawyer c++11

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

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

    B b;

    A(const B& _b = B())
        : b(_b)
    {}
};
Run Code Online (Sandbox Code Playgroud)

我用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())
                       ^
Run Code Online (Sandbox Code Playgroud)

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())
                    ^
Run Code Online (Sandbox Code Playgroud)

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

struct B
{
    int i = 0;
    B(){} // using B()=default; works only for clang++
};
Run Code Online (Sandbox Code Playgroud)

要么

struct B
{
    int i;
    B() : i(0) {} // classic c++98 initialization
};
Run Code Online (Sandbox Code Playgroud)

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

Ric*_*ith 83

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

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

struct A {
  struct B {
    int i = (A(), 0);
  };
  A() noexcept(!noexcept(B()));
};
Run Code Online (Sandbox Code Playgroud)

这有一个矛盾:B::B()是隐含noexcept当且仅当A()没有抛出,而A()不会引发当且仅当B::B()没有 noexcept.这方面还有许多其他周期和矛盾.

这由核心问题13601397跟踪.特别注意核心问题1397中的这个注释:

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

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

    A(const B& _b = B())
                    ^
Run Code Online (Sandbox Code Playgroud)

...因为Clang在解析默认初始化器之前解析默认参数,并且此默认参数将要求B已经解析的默认初始化器(为了隐式定义B::B()).

  • @aschepler是的,这里的诊断不是很好.我已经为此提交了llvm.org/PR16550. (4认同)