c++ c++11 initializer-list aggregate-initialization

c++ - ¿Cuáles son las reglas de la generación de constructor campo por campo?



c++11 initializer-list (3)

El código mostrado se compila sin problemas con gcc 6.1.1. Es probable que estés usando un compilador antiguo que no es totalmente compatible con C ++ 14:

$ cat t.C class S { public: int a = 0; }; void foo() { int a=4; S s{a}; } $ g++ -std=c++1z -g -c -o t.o t.C $ g++ --version g++ (GCC) 6.1.1 20160510 (Red Hat 6.1.1-2) Copyright (C) 2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

He encontrado que la posibilidad de utilizar la sintaxis de la lista de inicializadores para una clase depende de si los campos de la clase tienen o no valores predeterminados. ¿Por qué?

Para ser precisos, considere el siguiente código:

class S { public: int a; }; ... int a; S s{ a };

Se compila sin ningún problema. Pero si agrego un valor predeterminado al campo de clase, deja de construir:

class S { public: int a = 0; }; ... int a; S s{ a };

Error 1 error C2440: ''inicializando'': no ​​se puede convertir de ''initializer-list'' a ''S''

¿Por qué? ¿Qué más influye en esa generación de constructores?


En C ++ 14 , su código es válido y debe compilarse con cualquier compilador compatible con C ++ 14.

En C ++ 11 sin embargo:

Si no tiene un valor predeterminado para a , su tipo es un agregado y, por lo tanto , se puede realizar la inicialización agregada :

Un agregado es uno de los siguientes tipos:

  • tipo de matriz

  • tipo de clase (típicamente, estructura o unión), que tiene

    • No hay miembros de datos no estáticos privados o protegidos
    • ningún constructor proporcionado por el usuario, incluidos los heredados de bases públicas (desde C ++ 17) (se permiten constructores predeterminados o eliminados explícitamente) (desde C ++ 11)
    • no clases virtuales, privadas o protegidas (desde C ++ 17)
    • no hay funciones de miembro virtual
    • sin inicializadores de miembros predeterminados ( desde C ++ 11, hasta C ++ 14 )

Tan pronto como agregue un valor predeterminado para el atributo a , su inicialización agregada ya no podrá realizarse ya que su tipo deja de ser un agregado.


En ambos casos, el constructor por defecto de S no toma argumentos. La forma de la clase no afecta la generación del constructor predeterminado. Además, no hay un constructor implícitamente generado que tome int .

Si S es un agregado , entonces el uso S s = { arguments_opt }; No invoca el constructor de S. En su lugar, invoca algo llamado inicialización agregada . Los agregados son las únicas clases tales que los objetos de esa clase pueden crearse sin una invocación del constructor.

Solo si S no es un agregado, S s = { arguments_opt }; intente hacer coincidir la lista de argumentos con los parámetros de un constructor de S

(Como lo explicaron otros, en C ++ 11, proporcionar un inicializador con o sin llave para un miembro de datos no estáticos hace que la clase no sea un agregado).