¿Realmente necesito implementar un constructor proporcionado por el usuario para objetos const?

Tengo el código:

class A { public: A() = default; private: int i = 1; }; int main() { const A a; return 0; } 

Comstack bien en g ++ (ver ideone ), pero falla en clang ++ con error:

la inicialización predeterminada de un objeto de tipo const ‘const A’ requiere un constructor predeterminado proporcionado por el usuario

Informé sobre este problema en LLVM bug-tracker y lo recibí INVALID.

Lo veo absolutamente inútil tratar de convencer a los desarrolladores de clang. Por otro lado, no veo el motivo de tal restricción.


¿Puede alguien aconsejar, si el estándar C ++ 11 de alguna manera implica que este código no es válido? ¿O debería informar un error a g ++? ¿O tal vez hay suficiente libertad en las reglas del lenguaje para manejar este código de muchas maneras?

N3797 §8.5 / 7 dice:

Si un progtwig solicita la inicialización predeterminada de un objeto de un tipo const-calificado T, T será un tipo de clase con un constructor predeterminado proporcionado por el usuario.

No hay más ejemplos o explicaciones de esto. Estoy de acuerdo, parece bastante extraño. Además, la regla se actualizó en C ++ 11 para que fuera más restrictiva que en C ++ 03, cuando los tipos de clase necesitaban constructores declarados por el usuario . (Su constructor es declarado por el usuario).

La solución consiste en solicitar la inicialización del valor con {} , o utilizar la ingeniosa definición en inline fuera de clase de Dietmar.

GCC proporciona un diagnóstico (y bastante bueno, en referencia a los requisitos más nuevos de C ++ 11) si agrega otro miembro sin un inicializador.

  private: int i = 1; int j; 

 unmem.cpp:11:11: error: uninitialized const 'a' [-fpermissive] const A a; ^ unmem.cpp:1:7: note: 'const class A' has no user-provided default constructor class A { ^ unmem.cpp:3:5: note: constructor is not user-provided because it is explicitly defaulted in the class body A() = default; ^ unmem.cpp:7:9: note: and the implicitly-defined constructor does not initialize 'int A::j' int j; 

La fuente GCC se refiere a DR 253 , ¿Por qué deben inicializarse los objetos const vacíos o totalmente inicializados? Este es un problema abierto en el estándar, actualizado por última vez en agosto de 2011 (posterior a C ++ 11) con esta nota:

Si el constructor predeterminado implícito inicializa todos los subobjetos, no se requiere ningún inicializador.

Por lo tanto, mientras que Clang cumple con C ++ 11 (y cumplirá como está con C ++ 14), GCC está implementando las últimas ideas del comité de estandarización.

Archivado un error de GCC . Predigo que necesitarás: un -pedantic para obtener un diagnóstico cuando (y si) el error está solucionado.

Tenga en cuenta que puede convertir fácilmente su clase en una que tenga un constructor predeterminado definido por el usuario:

 class A { public: A(); private: int i = 1; }; inline A::A() = default; 

De acuerdo con 8.4.2 [dcl.fct.def.default], párrafo 4:

… Una función miembro especial es proporcionada por el usuario si es declarada por el usuario y no predeterminada de manera predeterminada o eliminada en su primera statement. …

Esto establece implícitamente que una función que no está explícitamente predeterminada en su primera statement no es proporcionada por el usuario. En combinación con 8.5 [dcl.init] párrafo 6

… Si un progtwig solicita la inicialización predeterminada de un objeto de un tipo const-calificado T, T será un tipo de clase con un constructor predeterminado proporcionado por el usuario.

parece claro que no puede usar un constructor predeterminado predeterminado en su primera statement para inicializar un objeto const . Sin embargo, puede usar una definición predeterminada si no es la primera statement como se hace en el código anterior.

Editar: lo siguiente se basa en información desactualizada. Acabo de pasar por N3797 y esto es lo que encontré:

§ 8.5 / 7 [dcl.init]
Si un progtwig solicita la inicialización predeterminada de un objeto de un tipo const-calificado T, T será un tipo de clase con un constructor predeterminado proporcionado por el usuario.

Tenga en cuenta que la cita estándar en el siguiente enlace dice declarada por el usuario .


El siguiente progtwig comstack en g ++ pero no clang ++:

 struct A {}; void f() { A const a; } 

Y podría estar relacionado con este informe de error donde fue “arreglado”. g ++ no puede comstackrlo una vez que contiene miembros de datos a menos que estén inicializados. Tenga en cuenta que int member = 1 ya no hará de A un POD. Comparativamente, clang ++ rechaza todas las permutaciones (clases vacías y miembros de datos inicializados o no). Para una interpretación de lo que significa el estándar en el siguiente párrafo:

§ 8.5 / 9 [dcl.init] dice:

Si no se especifica ningún inicializador para un objeto, y el objeto es de tipo de clase no POD (posiblemente un CV), el objeto se inicializará por defecto; si el objeto es de tipo const-qualified, el tipo de clase subyacente tendrá un constructor predeterminado declarado por el usuario. De lo contrario, si no se especifica ningún inicializador para un objeto, el objeto y sus subobjetos, si los hay, tienen un valor inicial indeterminado; si el objeto o cualquiera de sus subobjetos son de tipo const, el progtwig está mal formado.

Consulte ¿Por qué C ++ requiere que un constructor predeterminado proporcionado por el usuario cree de forma predeterminada un objeto const? . Supuestamente, el progtwig está mal formado if the object is of const-qualified POD type, and there is no initializer specified (because POD are not default initialized). Observe cómo g ++ se comporta para lo siguiente:

 struct A {int a;}; struct B {int a = 1;}; int main() { A a; B b; const A c; // A is POD, error const B d; // B is not POD, contains data member initializer, no error }