Назначенные инициализаторы в 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 flags.

Как вы можете видеть выше, как структуры, так PersonиEmployee агрегаты, но инициализация Employeeагрегата невозможна с использованием назначенных инициализаторов.

Может ли кто-нибудь объяснить мне, почему?

MateuszGierczak
источник
Я не знаю, решит ли это вашу проблему, но вы не можете наследовать здесь ...struct Employee : public Person
skratchi.at
@ skratchi.at stackoverflow.com/a/3965003/11683
GSerg
@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 };

В этом случае прямой базовый класс инициализируется указанным списком инициализаторов, а класс Employe в целом инициализируется неназначенным списком инициализаторов.

Влад из Москвы
источник
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 ++.

Jarod42
источник