Initialiseurs désignés en C ++ 20

25

J'ai une question sur l'une des fonctionnalités c ++ 20, les initialiseurs désignés (plus d'informations sur cette fonctionnalité ici )

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

Ce code a été compilé avec gcc 9.2.0 et -Wall -Wextra -std=gnu++2aflags.

Comme vous pouvez le voir ci-dessus, les deux structures Personet Employeesont des agrégats, mais l'initialisation d' Employeeagrégat n'est pas possible à l'aide des initialiseurs désignés.

Quelqu'un pourrait-il m'expliquer pourquoi?

MateuszGierczak
la source
Je ne sais pas si cela résout votre problème, mais vous ne pouvez pas hériter du public ici ...struct Employee : public Person
skratchi.at
@ skratchi.at stackoverflow.com/a/3965003/11683
GSerg
@GSerg Ok, eh bien ... je n'ai jamais perdu une pensée à ce sujet, car j'utilise publicou à privatechaque fois ... merci quand même
skratchi.at
quelle est votre erreur exacte que vous obtenez ??
skratchi.at
2
@ skratchi.at structs hérite publiquement par défaut
idclev 463035818

Réponses:

15

Selon la norme C ++ 20 (9.3.1 Agrégats. P. # 3)

(3.1) - Si la liste d'initialiseurs est une liste d'initialiseurs désignés, l'agrégat doit être de type classe, l'identificateur dans chaque désignateur doit nommer un membre de données direct non statique de la classe et les éléments explicitement initialisés de l'agrégat sont les éléments qui sont ou contiennent ces membres.

Vous ne pouvez donc pas utiliser la liste d'initialisation désignée pour initialiser les membres de données des classes de base.

Utilisez plutôt l'initialisation de liste habituelle comme

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

ou

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

ou comme @ Jarod42 l'a souligné dans un commentaire, vous pouvez écrire

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

Dans ce cas, la classe de base directe est initialisée par une liste d'initialisation désignée tandis que la classe Employe dans son ensemble est initialisée par une liste d'initialisation non désignée.

Vlad de Moscou
la source
3
ou un mélange: Employee e1{ { .name{"John"}, .surname{"Wick"}, .age{40} }, 50000 };.
Jarod42
@ Jarod42 Oui, il compile.
Vlad de Moscou
5

Vous pouvez avoir plusieurs champs avec le même nom de différentes bases,

donc logiquement, vous devez fournir le nom de la base recherchée, mais il semble qu'il n'y ait aucun moyen de le faire.

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

De plus, l'initialisation désignée par C ++ est plus contrainte que C:

Remarque: l'initialisation désignée dans le désordre, l'initialisation désignée imbriquée, le mélange des initialiseurs désignés et des initialiseurs réguliers et l'initialisation désignée des tableaux sont tous pris en charge dans le langage de programmation C, mais ne sont pas autorisés en C ++.

Jarod42
la source