Inicializadores designados em C ++ 20

25

Tenho uma pergunta sobre um dos recursos do c ++ 20, inicializadores designados (mais informações sobre esse recurso aqui )

#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 foi compilado com o gcc 9.2.0 e -Wall -Wextra -std=gnu++2asinalizadores.

Como você pode ver acima, ambas as estruturas Persone Employeesão agregados, mas a inicialização do Employeeagregado não é possível usando inicializadores designados.

Alguém poderia me explicar o porquê?

MateuszGierczak
fonte
Eu não sei se ele resolve o seu problema, mas você não pode herdar pública aqui ...struct Employee : public Person
skratchi.at
@ skratchi.at stackoverflow.com/a/3965003/11683
GSerg
@GSerg Ok, bem ... eu nunca perdi um pensamento nisso, já que eu uso publicou privatetoda vez ... obrigado mesmo assim
skratchi.at
qual é o seu erro exato que você recebe ??
Skratchi.at 15/11/19
2
@ skratchi.at structs herdam publicamente por padrão
idclev 463035818

Respostas:

15

De acordo com o padrão C ++ 20 (9.3.1 Agregados. P. # 3)

(3.1) - Se a lista de inicializadores for uma lista de inicializadores designados, o agregado deve ser do tipo de classe, o identificador em cada designador deve nomear um membro de dados não estáticos diretos da classe e os elementos explicitamente inicializados do agregado são os elementos que são ou contêm esses membros.

Portanto, você não pode usar a lista inicializada designada para inicializar membros de dados das classes base.

Use a inicialização usual da lista, como

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

ou

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

ou como @ Jarod42 apontou em um comentário que você pode escrever

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

Nesse caso, a classe base direta é inicializada por uma lista de inicializadores designada, enquanto a classe Employe no total é inicializada por uma lista de inicializadores não designados.

Vlad de Moscou
fonte
3
ou uma mistura: Employee e1{ { .name{"John"}, .surname{"Wick"}, .age{40} }, 50000 };.
Jarod42
@ Jarod42 Sim, ele compila.
Vlad de Moscou
5

Você pode ter vários campos com o mesmo nome de diferentes bases,

portanto, logicamente, você deve fornecer o nome da base desejada, mas parece que não há como fazê-lo.

// 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}};

Além disso, a inicialização designada por C ++ é mais restrita que C:

Nota: inicialização designada fora de ordem, inicialização designada aninhada, mistura de inicializadores designados e inicializadores regulares e inicialização designada de matrizes são todos suportados na linguagem de programação C, mas não são permitidos no C ++.

Jarod42
fonte