Inicializadores designados en C ++ 20

25

Tengo una pregunta sobre una de las características de c ++ 20, inicializadores designados (más información sobre esta característica aquí )

#include <iostream>

constexpr unsigned DEFAULT_SALARY {10000};

struct Person
{
    std::string name{};
    std::string surname{};
    unsigned age{};
};

struct Employee : Person
{
    unsigned salary{DEFAULT_SALARY};
};

int main()
{
    std::cout << std::boolalpha << std::is_aggregate_v<Person> << '\n'; // true is printed
    std::cout << std::boolalpha << std::is_aggregate_v<Employee> << '\n'; // true is printed

    Person p{.name{"John"}, .surname{"Wick"}, .age{40}}; // it's ok
    Employee e1{.name{"John"}, .surname{"Wick"}, .age{40}, .salary{50000}}; // doesn't compile, WHY ?

    // For e2 compiler prints a warning "missing initializer for member 'Employee::<anonymous>' [-Wmissing-field-initializers]"
    Employee e2 {.salary{55000}}; 
}

Este código fue compilado con gcc 9.2.0 y -Wall -Wextra -std=gnu++2aflags.

Como puede ver arriba, ambas estructuras Persony Employeeson agregados, pero la inicialización del Employeeagregado no es posible utilizando inicializadores designados.

¿Podría alguien explicarme por qué?

MateuszGierczak
fuente
No sé si resuelve su problema, pero no puede heredar pública aquí ...struct Employee : public Person
skratchi.at
@ skratchi.at stackoverflow.com/a/3965003/11683
GSerg
@GSerg Ok, bueno ... nunca desperdicié un pensamiento en eso, ya que uso publico privatecada vez ... gracias de todos modos
skratchi.at
¿Cuál es tu error exacto que obtienes?
skratchi.at
2
@ skratchi.at structs hereda públicamente por defecto
idclev 463035818

Respuestas:

15

De acuerdo con el estándar C ++ 20 (9.3.1 Agregados. P. # 3)

(3.1) - Si la lista de inicializadores es una lista de inicializadores designada, el agregado será de tipo de clase, el identificador en cada designador nombrará un miembro de datos no estático directo de la clase y los elementos inicializados explícitamente del agregado son los elementos que son, o contienen, esos miembros.

Por lo tanto, no puede usar la lista de inicializadores designada para inicializar miembros de datos de clases base.

Utilice en su lugar la inicialización de lista habitual como

Employee e1{ "John", "Wick", 40, 50000 };

o

Employee e1{ { "John", "Wick", 40 }, 50000 };

o como @ Jarod42 señaló en un comentario que puedes escribir

Employee e1{ { .name{"John"}, .surname{"Wick"}, .age{40} }, 50000 };

En este caso, la clase base directa se inicializa mediante una lista de inicializadores designada, mientras que la clase Empleado en su totalidad se inicializa mediante una lista de inicializadores no designados.

Vlad de Moscú
fuente
3
o una mezcla de: Employee e1{ { .name{"John"}, .surname{"Wick"}, .age{40} }, 50000 };.
Jarod42
@ Jarod42 Sí, se compila.
Vlad desde Moscú el
5

Es posible que tenga varios campos con el mismo nombre desde diferentes bases,

lógicamente, debe proporcionar el nombre de la base deseada, pero parece que no hay forma de hacerlo.

// Invalid too:
Employee e1{.Person.name{"John"}, .Person.surname{"Wick"}, .Person.age{40}, .salary{50000}};
Employee e2{.Person{.name{"John"}, .surname{"Wick"}, .age{40}}, .salary{50000}};

Además, la inicialización designada por C ++ está más restringida que C:

Nota: la inicialización designada fuera de orden, la inicialización designada anidada, la mezcla de inicializadores designados e inicializadores regulares y la inicialización designada de matrices son compatibles con el lenguaje de programación C, pero no están permitidos en C ++.

Jarod42
fuente