Error using class initialization of a non-static data element and nested class constructor

The following code is pretty trivial, and I expected it to compile.

struct A { struct B { int i = 0; }; B b; A(const B& _b = B()) : b(_b) {} }; 

I tested this code with g ++ versions 4.7.2, 4.8.1, clang ++ 3.2 and 3.3. Besides the fact that g ++ 4.7.2 segfaults to this code ( http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57770 ), other proven compilers provide error messages that do not explain much.

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 and 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()) ^ 

The ability to compile this code is possible and does not seem to matter. There are two options:

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

or

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

Is this code really wrong or are the compilers wrong?

+82
c ++ language-lawyer c ++ 11
Jul 02 '13 at 16:03
source share
2 answers

Is this code really wrong or are the compilers wrong?

Good. The standard has a defect - it says that A is considered complete when analyzing the initializer for B::i and that B::B() (which uses the initializer for B::i ) can be used in the definition of A This is clearly cyclical. Consider this:

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

This has a contradiction: B::B() implicitly noexcept iff A() does not throw, and A() does not throw iff B::B() does not noexcept . There are a number of other cycles and contradictions in this area.

The main problems 1360 and 1397 are tracked. Pay particular attention to this note in the main problem 1397:

Perhaps the best way to solve this problem would be to make it incorrect for a non-static element of a data element initializer to use the default constructor of its class.

This is a special case of the rule that I applied in Clang to solve this problem. The Clang rule is that the standard default constructor for a class cannot be used before the non-static element initializers for this class are parsed. Therefore, Clang issues the diagnostics here:

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

... because Clang parses the default arguments before it parses the default initializers, and this default argument will require that the default B initializers are already parsed (in order to implicitly define B::B() ).

+72
Jul 02 '13 at 21:24
source share

Perhaps this is the problem:

ยง12.1 5. The default constructor, which by default is not defined as remote, is implicitly defined when it is odr- used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration

Thus, the default constructor is generated at the first scan, but the search will not work, because A is not completely defined and B inside A. Therefore, it will not be found.

0
Jul 02 '13 at 19:16
source share



All Articles