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).