Позначені ініціалізатори в C ++ 20


25

У мене запитання щодо однієї з функцій c ++ 20, призначених ініціалізаторами (більше інформації про цю функцію тут )

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

Цей код був складений з gcc 9.2.0 та -Wall -Wextra -std=gnu++2aпрапорами.

Як ви бачите вище, обидві структури Personі Employeeє агрегатами, але ініціалізація Employeeсукупності неможлива за допомогою призначених ініціалізаторів.

Може хтось мені пояснить, чому?


Я не знаю, чи вирішує вона вашу проблему, але ви можете не успадкувати публіку тут ...struct Employee : public Person
skratchi.at


@GSerg Добре, ну ... я ніколи не гаяв думки з цього приводу, оскільки використовую publicабо privateкожен раз ... все одно дякую
skratchi.at

Яку точну помилку ви отримаєте ??
skratchi.at

2
@ skratchi.at structs успадкувати публічно за замовчуванням
idclev 463035818

Відповіді:


15

Відповідно до стандарту C ++ 20 (9.3.1 Агрегати. Стор. №3)

(3.1) - Якщо список ініціалізатора є списком призначених ініціалізаторів, то агрегат повинен бути типу класу, ідентифікатор у кожному позначувачі повинен називати прямий нестатичний член даних класу та явно ініціалізовані елементи сукупності - це елементи, які є або містять ці члени.

Тому ви не можете використовувати призначений список ініціалізатора для ініціалізації членів даних базових класів.

Використовуйте замість звичайної ініціалізації списку, як

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

або

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

або як вказав @ Jarod42 у коментарі, який ви можете написати

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

У цьому випадку прямий базовий клас ініціалізується призначеним списком ініціалізатора, тоді як клас Співробітник в цілому ініціалізується невстановленим списком ініціалізатора.


3
або суміш: Employee e1{ { .name{"John"}, .surname{"Wick"}, .age{40} }, 50000 };.
Jarod42

@ Jarod42 Так, це компілюється.
Влад з Москви

5

У вас може бути кілька полів з однаковою назвою з різних баз,

так логічно, ви повинні вказати ім'я шуканої бази, але, здається, немає способу це зробити.

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

Крім того, призначена ініціалізація C ++ є більш обмеженою, ніж C:

Примітка: ініціалізація, призначена поза порядком, вкладена призначена ініціалізація, змішування призначених ініціалізаторів та звичайних ініціалізаторів та призначена ініціалізація масивів всі підтримуються на мові програмування C, але не допускаються в C ++.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.