Inizializzatori designati in C ++ 20


25

Ho una domanda su una delle funzionalità di c ++ 20, inizializzatori designati (maggiori informazioni su questa funzione qui )

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

Questo codice è stato compilato con gcc 9.2.0 e -Wall -Wextra -std=gnu++2aflag.

Come puoi vedere sopra, entrambe le strutture Persone Employeesono aggregati ma l'inizializzazione Employeedell'aggregato non è possibile utilizzando gli inizializzatori designati.

Qualcuno potrebbe spiegarmi perché?


Non so se risolve il tuo problema, ma potresti non ereditare il pubblico qui ...struct Employee : public Person
skratchi.at


@GSerg Ok, beh ... non ci ho mai pensato, visto che lo uso publico privateogni volta ... grazie comunque
skratchi.at

qual è il tuo errore esatto che ricevi ??
skratchi.at,

2
@ skratchi.at structs eredita pubblicamente per impostazione predefinita
idclev 463035818

Risposte:


15

Secondo lo standard C ++ 20 (9.3.1 Aggregati. P. # 3)

(3.1) - Se l'elenco di inizializzatori è un elenco di inizializzatori designato, l'aggregato deve essere di tipo classe, l'identificatore in ciascun designatore deve nominare un membro di dati diretto non statico della classe e gli elementi esplicitamente inizializzati dell'aggregato sono gli elementi che sono o contengono quei membri.

Pertanto, non è possibile utilizzare l'elenco di inizializzatori designato per inizializzare i membri dei dati delle classi di base.

Usa invece la solita inizializzazione dell'elenco come

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

o

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

o come ha sottolineato @ Jarod42 in un commento che puoi scrivere

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

In questo caso la classe base diretta viene inizializzata da un elenco di inizializzatori designati mentre la classe Employe nel suo insieme viene inizializzata da un elenco di inizializzatori non designati.


3
o un mix: Employee e1{ { .name{"John"}, .surname{"Wick"}, .age{40} }, 50000 };.
Jarod42,

@ Jarod42 Sì, si compila.
Vlad da Mosca,

5

Potresti avere diversi campi con lo stesso nome da basi diverse,

quindi logicamente, dovresti fornire il nome della base desiderata, ma sembra che non ci sia modo di farlo.

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

Inoltre, l'inizializzazione designata da C ++ è più limitata di C:

Nota: l'inizializzazione designata non ordinata, l'inizializzazione designata nidificata, la miscelazione di inizializzatori designati e inizializzatori regolari e l'inizializzazione designata di array sono tutti supportati nel linguaggio di programmazione C, ma non sono consentiti in C ++.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.