Inicialización de agregado
Inicializa un agregado a partir de una lista de inicializadores entre llaves.
Contenido |
[editar] Sintaxis
T objeto = {arg1, arg2, ...};
|
(1) | ||||||||
T objeto {arg1, arg2, ...};
|
(2) | (desde C++11) | |||||||
T objeto = { .designador = arg1 , .designador { arg2 } ... };
|
(3) | (desde C++20) | |||||||
T objeto { .designador = arg1 , .designador { arg2 } ... };
|
(4) | (desde C++20) | |||||||
T objeto (arg1, arg2, ...);
|
(5) | (desde C++20) | |||||||
[editar] Explicación
La inicialización de agregado inicializa agregados. Es una forma de inicialización de lista (desde C++11) o inicialización directa (desde C++20)
Un agregado es uno de los siguientes tipos:
- tipo array;
- tipo clase (típicamente, struct o union), que no tiene:
- datos miembros no estáticos directos (desde C++17) privados o protegidos;
|
(hasta C++11) |
|
(desde C++11) (hasta C++17) |
|
(desde C++17) (hasta C++20) |
|
(desde C++20) |
- clases base virtuales, privadas o protegidas (desde C++17);
- funciones miembro virtuales;
| (desde C++11) (hasta C++14) |
Los efectos de la inicialización de agregado son:
- Cada base pública directa, (desde C++17) elemento de array, o miembro de clase no estático, en el orden de subíndice o de aparición en la definición de la clase, se inicializa mediante la inicialización de copia desde la cláusula correspondiente en la lista de inicializadores.
- Si la cláusula de inicializadores es una expresión, se permiten las conversiones implícitas como se permite en la inicialización de copia, excepto que para la forma de inicialización de lista se prohiben las conversiones de estrechamiento (desde C++11).
- Si la cláusula de inicializadores es una lista anidada de inicialización entre llaves (lo que no es una expresión), el elemento de array, miembro de clase correspondiente, o base pública (desde C++17) es inicializado mediante la inicialización de lista desde esta cláusula: la inicialización de agregado es recursiva.
- Si el objeto es un array de tamaño desconocido, y la lista de inicializadores entre llaves suplementada tiene
nclaúsulas, el tamaño del array esn(observa que en este caso el objeto no puede ser un dato miembro no estático: un miembro debe tener un tipo completo).
- Los datos miembro estáticos y campos de bits sin nombre se omiten durante la inicialización de agregado.
- Si el número de cláusulas de inicializadores excede el número de miembros y bases (desde C++17) a inicializar, el programa está mal formado.
|
(hasta C++11) |
|
(desde C++11) |
- Cuando una unión se inicializa con la inicialización de agregado, solamente se inicializa su primer dato miembro no estático.
Si la inicialización de agregado utiliza la sintaxis de inicialización de lista de copia (T a = {args...}), (hasta C++14)las llaves en torno a las listas de inicializadores anidadas pueden elidirse (omitirse), en cuyo caso se utilizan cuantas cláusulas de inicializadores sean necesarias para inicializar cada miembro o elemento del subagregado correspondiente, y las cláusulas de inicializadores subsecuentes se utilizan para inicializar los miembros siguientes del objeto. Sin embargo, si el objeto tiene un subagregado sin miembros (una estructura vacía o una estructura que alberga solamente miembros estáticos), no se permite la elisión de las llaves, y se tiene que usar una lista anidada vacía {} .
Inicializadores designadosLas formas de sintaxis (3,4) se conocen como inicializadores designados: cada designador debe nombrar un dato miembro directo no estático de T, y todos los designadores utilizados en la expresión deben aparecer en el mismo orden que los datos miembro de T. struct A { int x; int y; int z; }; A a{.y = 2, .x = 1}; // ERROR: el orden del designador no coincide con el orden de declaración A b{.x = 1, .z = 2}; // de acuerdo, b.y inicializada a 0 Cada dato miembro directo no estático nombrado por el inicializador designado se inicializa desde el inicializador correspondiente con llaves o signo igual que sigue al designador. Se prohíben las conversiones de estrechamiento. Un inicializador designado puede utilizarse para inicializar una unión (union) en un estado distinto del primero. Solamente puede proporcionarse un inicializador para una unión. union u { int a; const char* b; }; u f = { .b = "asdf" }; // de acuerdo, el miembro activo de la unión es b u g = { .a = 1, .b = "asdf" }; // ERROR, solamente se puede proporcionar un inicializador Para un agregado que no es de tipo unión, los elementos para los cuales no se proporciona un inicializador designado se inicializan de la misma manera como se describe anteriormente para el caso donde el número de cláusulas de inicializadores es menor que el número de miembros (los inicializadores de miembros por defecto, cuando se proporcionan, de otra manera, inicialización de lista): struct A { string str; int n = 42; int m = -1; }; A{.m=21} // Inicializa str con {}, que llama al constructor por defecto // entonces inicializa a n con = 42 // entonces inicializa a m con = 21 Si el agregado que se inicializa con una cláusula de inicializador designado tiene un miembro de tipo unión anónima, el inicializador designado correspondiente deberá nombrar uno de los miembros de esa unión anónima. Nota: la inicialización designada fuera de orden, la inicialización designada anidada, la mezcla de inicializadores designados con inicializadores regulares, y la inicialización designada de arrays, se soportan todas en el lenguaje de programación C, pero no se permiten en C++. struct A { int x, y; }; struct B { struct A a; }; struct A a = {.y = 1, .x = 2}; // C válido, C++ inválido (fuera de orden) int arr[3] = {[1] = 5}; // C válido, C++ inválido (array) struct B b = {.a.x = 0}; // C válido, C++ inválido (anidado) struct A a = {.x = 1, 2}; // C válido, C++ inválido (mezclado) |
(desde C++20) |
[editar] Arrays de caracteres
Los arrays de tipos carácter (char, signed char, unsigned char, char8_t, char16_t, char32_t y wchar_t), pueden inicializarse desde un literal de cadena apropriado, opcionalmente entre llaves. Los caracteres sucesivos en el literal de cadena (que incluye el carácter terminador nulo implícito) inicializan los elementos del array. Si el tamaño del array se especifica y es más grande que el número de caracteres en el literal de cadena, los caracteres restantes se inicializan mediante la inicialización cero.
char a[] = "abc"; // equivalente a char a[4] = {'a', 'b', 'c', '\0'}; // unsigned char b[3] = "abc"; // ERROR: cadena de inicializadores demasiado larga unsigned char b[5]{"abc"}; // equivalente a unsigned char b[5] = {'a', 'b', 'c', '\0', '\0'}; wchar_t c[] = {L"кошка"}; // llaves son opcionales // equivalente a wchar_t c[6] = {L'к', L'о', L'ш', L'к', L'а', L'\0'};
[editar] Notas
Una clase de agregado o array puede incluir bases públicas (desde C++17), miembros o elementos que no son agregados, que se inicializan como se describe anteriormente (por ejemplo, la inicialización de copia de la cláusula de inicializadores correspondiente).
Hasta C++11, las conversiones de estrechamiento estaban permitidas en la inicialización de agregado, pero ya no están permitidas, excepto que, a partir de C++20, están permitidas cuando la inicialización de agregado usa paréntesis.
Hasta C++11, la inicialización de agregado no podía usarse en una lista de inicializadores de constructor debido a restricciones de sintaxis.
Hasta C++14, la forma de inicialización directa T a {args...} no permitía la elisión de las llaves.
En C, un array de caracteres de tamaño uno menor que el tamaño del literal de cadena puede inicializarse desde un literal de cadena; el array resultante no tiene terminación nula. Esto no está permitido en C++.
[editar] Ejemplo
#include <string> #include <array> struct S { int x; struct Foo { int i; int j; int a[3]; } b; }; union U { int a; const char* b; }; int main() { S s1 = { 1, { 2, 3, {4, 5, 6} } }; S s2 = { 1, 2, 3, 4, 5, 6}; // lo mismo, pero con elisión de llaves S s3{1, {2, 3, {4, 5, 6} } }; // lo mismo, usando sintaxis de inicialización de lista directa S s4{1, 2, 3, 4, 5, 6}; // ERROR en C++11: elisión de llaves solo se permite con signo igual // de acuerdo en C++14 int ar[] = {1,2,3}; // ar es int[3] int ab[] (1, 2, 3); // (C++20) ab is int[3] // char cr[3] = {'a', 'b', 'c', 'd'}; // demasiadas cláusulas de inicializadores char cr[3] = {'a'}; // array inicializado como {'a', '\0', '\0'} int ar2d1[2][2] = {{1, 2}, {3, 4}}; // array 2D totalmente con llaves: {1, 2} // {3, 4} int ar2d2[2][2] = {1, 2, 3, 4}; // elisión de llaves: {1, 2} // {3, 4} int ar2d3[2][2] = {{1}, {2}}; // solamente la primera columna: {1, 0} // {2, 0} std::array<int, 3> std_ar2{ {1,2,3} }; // std::array es un agregado std::array<int, 3> std_ar1 = {1, 2, 3}; // de acuerdo con la elisión de llaves int ai[] = { 1, 2.0 }; // conversión de estrechamiento de double a int: // ERROR en C++11, de acuerdo en C++03 std::string ars[] = {std::string("uno"), // inicialización de copia "dos", // conversión, luego inicialización de copia {'t', 'r', 'e', 's'} }; // inicialización de lista U u1 = {1}; // de acuerdo, primer miembro de la unión // U u2 = { 0, "asdf" }; // ERROR: demasiados inicializadores para la unión // U u3 = { "asdf" }; // ERROR: conversión inválida a int } // agregado struct base1 { int b1, b2 = 42; }; // no-agregado struct base2 { base2() : b3(42) {} int b3; }; // agregado en C++17 struct derivada : base1, base2 { int d; }; derivada d1{ {1, 2}, { }, 4}; // d1.b1 = 1, d1.b2 = 2, d1.b3 = 42, d1.d = 4 derivada d2{ { }, { }, 4}; // d2.b1 = 0, d2.b2 = 42, d2.b3 = 42, d2.d = 4
[editar] Véase también
| Documentación de C de Inicialización de estructuras y uniones
|

