El siguiente código es bastante trivial y esperaba que se compilara bien.
struct A
{
struct B
{
int i = 0;
};
B b;
A(const B& _b = B())
: b(_b)
{}
};
He probado este código con g ++ versión 4.7.2, 4.8.1, clang ++ 3.2 y 3.3. Aparte del hecho de que g ++ 4.7.2 segfaults en este código ( http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57770 ), los otros compiladores probados dan mensajes de error que no explican mucho.
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 y 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())
^
Hacer que este código sea compilable es posible y parece que no debería hacer ninguna diferencia. Hay dos opciones:
struct B
{
int i = 0;
B(){} // using B()=default; works only for clang++
};
o
struct B
{
int i;
B() : i(0) {} // classic c++98 initialization
};
¿Es este código realmente incorrecto o los compiladores están equivocados?
c++
c++11
language-lawyer
etam1024
fuente
fuente

internal compiler error: Segmentation faulta este código ...int i = 0menos que lo seastatic const int i = 0.B()como una llamada de función a un constructor. Usted no directamente "llamada" un constructor. Piense en esto como una sintaxis especial que crea un temporalB... y el constructor se invoca como solo una parte de ese proceso, en lo profundo del mecanismo que sigue.Bparece hacer que esto funcionegcc 4.7.Respuestas:
Bueno, tampoco. El estándar tiene un defecto: dice tanto que
Ase considera completo al analizar el inicializador paraB::icomo queB::B()(que usa el inicializador paraB::i) se puede usar dentro de la definición deA. Eso es claramente cíclico. Considera esto:Esto tiene una contradicción:
B::B()es implícitamentenoexceptiffA()no lanza, yA()no lanza iff no loB::B()es . Hay varios otros ciclos y contradicciones en esta área.noexceptEsto se rastrea mediante los problemas centrales 1360 y 1397 . Tenga en cuenta en particular esta nota en el número principal 1397:
Ese es un caso especial de la regla que implementé en Clang para resolver este problema. La regla de Clang es que un constructor predeterminado predeterminado para una clase no se puede usar antes de que se analicen los inicializadores de miembros de datos no estáticos para esa clase. Por lo tanto, Clang emite un diagnóstico aquí:
... porque Clang analiza los argumentos predeterminados antes de analizar los inicializadores predeterminados, y este argumento predeterminado requeriría que
Blos inicializadores predeterminados ya se hayan analizado (para poder definirlos implícitamenteB::B()).fuente
Tal vez éste es el problema:
Entonces, el constructor predeterminado se genera cuando se busca por primera vez, pero la búsqueda fallará porque A no está completamente definido y, por lo tanto, B dentro de A no se encontrará.
fuente
B bno es un problema, y encontrar métodos explícitos / un constructor declarado explícitamenteBno es un problema. Por lo que sería bueno ver una definición de por qué la búsqueda debe proceder de manera diferente aquí, así que "Ben el interiorAno se encuentra" en tan sólo este único caso, pero no los otros, antes de que podamos declarar el código ilegal por esta razón.=0archivoi = 0;. Pero sin eso=0, el código es válido y no encontrará un solo compilador que se queje del usoB()dentro de la definición deA.