c++ - morandi - const T{}; obras, const T; falla cuando T es un no-POD,
puente morandi maracaibo (2)
Así que parece que gcc está basando esto en el open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253 , aunque esto aún no está resuelto. Podemos ver esto en el siguiente gcc.gnu.org/bugzilla/show_bug.cgi?id=60284 que dice:
Esto es por diseño, porque como lo muestra el DR 253, el estándar normativo es defectuoso.
y el cambio de gcc que trajo esto en efecto dice:
Core 234: permite objetos const sin inicializador o constructor predeterminado proporcionado por el usuario si el constructor predeterminado inicializa todos los subobjetos.
Así que, técnicamente, el clang
es correcto y gcc
no es conforme, pero parece que creen que el DR 253
se resolverá a su favor. Esto tiene sentido si la preocupación principal es el valor inicial indeterminado que, por lo que puedo decir, es. Este cambio está documentado en las notas de la versión gcc 4.6 :
En 4.6.0 y 4.6.1, G ++ ya no permite que los objetos de tipo cualificado por primera vez se inicialicen por defecto a menos que el tipo tenga un constructor por defecto declarado por el usuario. En 4.6.2 G ++ implementa la resolución propuesta de DR 253, por lo que se permite la inicialización predeterminada si inicializa todos los subobjetos. El código que no se compila puede solucionarse proporcionando un inicializador, por ejemplo,
struct A { A(); }; struct B : A { int i; }; const B b = B();
Para empezar, tengo una estructura con un valor con un valor predeterminado
struct S {
int a = 1;
};
Este tipo puede construirse por defecto cuando no es const / non constexpr por gcc y clang. Bajo ambos, el valor std::is_pod<S>::value
es false
. El comportamiento extraño es el siguiente:
S s1; // works under both
const S s2{}; // works under both
const S s3; // only works in gcc, clang wants a user-provided constructor
Ninguno de los siguientes intentos hace una diferencia en el clang:
struct S {
int a = 1;
constexpr S() = default; // defaulted ctor
virtual void f() { } // virtual function, not an aggregate
private:
int b = 2; // private member, really not an aggregate
};
Lo único que puedo hacer para que esto funcione es agregar constexpr S() { }
explícitamente. Me parece realmente mal que const S s;
falla mientras const S s{};
Especialmente cuando el tipo no es un agregado.
El estándar me hace pensar que Clang tiene razón.
N4296 : 8.5 / 7
Si un programa solicita la inicialización predeterminada de un objeto de un tipo T calificado por la const, T será un tipo de clase con un constructor predeterminado proporcionado por el usuario
Entonces, ¿por qué gcc permite esto, y es S{};
¿No se está inicializando por defecto, incluso cuando el tipo no es un POD o un agregado?
const S s3;
Está cubierto por [dcl.init] / 12:
Si no se especifica un inicializador para un objeto, el objeto se inicializa por defecto.
Por lo tanto, como lo requiere su cotización, un constructor predeterminado proporcionado por el usuario debe estar presente. Añadiendo uno como asi
struct S {
int a = 1;
constexpr S(){}
};
Luego hace que la declaración se compile bien .
[..] especialmente cuando el tipo no es un agregado.
S
es un agregado en su caso, y la razón por la cual const S s{}
es válida. La inicialización agregada se aplica para const S s{}
, y todo está bien.
Si S
no es un agregado,
La inicialización de lista de un objeto o referencia de tipo T se define de la siguiente manera:
- Si
T
es un agregado, se realiza la inicialización agregada (8.5.1).- De lo contrario, si la lista de inicializadores no tiene elementos y
T
es un tipo de clase con un constructor predeterminado, el objeto se inicializa con valores.
Ahora considere la definición de inicialización de valor:
Para inicializar con valor un objeto de tipo
T
significa:
- si
T
es un tipo de clase (posiblemente cv calificado) (Cláusula 9) sin un constructor predeterminado (12.1) o un constructor predeterminado que sea proporcionado o eliminado por el usuario, entonces el objeto se inicializa por defecto;- si
T
es un tipo de clase (posiblemente cv calificado) sin un constructor predeterminado proporcionado o eliminado por el usuario, entonces el objeto se inicializa con cero y se comprueban las restricciones semánticas para la inicialización predeterminada , y siT
tiene un constructor predeterminado no trivial , el objeto está inicializado por defecto;
El ctor predeterminado es de hecho no trivial ya que un miembro tiene un inicializador ([class.ctor] /4.9), pero eso es irrelevante ya que las restricciones se verifican de cualquier manera. De ahí la inicialización por defecto que es, y la línea
const S s{};
Es tan válido (o no válido) como
const S t;
Entonces, ¿por qué gcc permite esto
Bien:
Hablando en términos de la norma actual, GCC no es compatible; Véase más arriba.
Hay un problema activo de CWG, open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253 , creado hace quince años, que cubre un escenario similar. La nota final sobre este de una reunión de 2011 dice
Si el constructor predeterminado implícito inicializa todos los subobjetos, no se requiere un inicializador.
Ese es el caso del constructor predeterminado implícito para
S
, y esto haría que todas sus líneas sean válidas.Los desarrolladores de GCC (p. Ej., here ) implicaron que, dado que el comité estuvo de acuerdo básicamente con la resolución anterior, el comportamiento actual de GCC es factible y no debe ajustarse . Por lo tanto, se podría argumentar que GCC tiene razón y que se rompe la norma.