Chỉ định khởi tạo trong C ++ 20


25

Tôi đã có một câu hỏi về một trong các tính năng c ++ 20, các trình khởi tạo được chỉ định (thông tin thêm về tính năng này tại đây )

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

Mã này được biên dịch với gcc 9.2.0 và -Wall -Wextra -std=gnu++2acờ.

Như bạn có thể thấy ở trên, cả hai cấu trúc PersonEmployeelà tổng hợp nhưng việc khởi tạo Employeetổng hợp là không thể sử dụng các công cụ khởi tạo được chỉ định.

Ai đó có thể giải thích cho tôi tại sao?


Tôi không biết nếu nó giải quyết vấn đề của bạn, nhưng bạn có thể không thừa kế công khai ở đây ...struct Employee : public Person
skratchi.at


@GSerg Ok, tốt ... Tôi chưa bao giờ lãng phí một suy nghĩ về điều đó, vì tôi sử dụng publichoặc privatemọi lúc ... cảm ơn dù sao đi nữa
skratchi.at

lỗi chính xác của bạn là gì ??
skratchi.at

2
@ skratchi.at structs kế thừa công khai theo mặc định
idclev 463035818

Câu trả lời:


15

Theo Tiêu chuẩn C ++ 20 (Tổng hợp 9.3.1. Trang 3)

(3.1) - Nếu danh sách trình khởi tạo là danh sách khởi tạo được chỉ định, tập hợp sẽ là loại lớp, mã định danh trong mỗi người chỉ định sẽ đặt tên cho thành viên dữ liệu không tĩnh trực tiếp của lớp và các phần tử được khởi tạo rõ ràng của tổng hợp là những yếu tố đang hoặc chứa những thành viên đó.

Vì vậy, bạn không thể sử dụng danh sách trình khởi tạo được chỉ định để khởi tạo thành viên dữ liệu của các lớp cơ sở.

Sử dụng thay vì khởi tạo danh sách thông thường như

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

hoặc là

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

hoặc như @ Jarod42 chỉ trong một bình luận bạn có thể viết

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

Trong trường hợp này, lớp cơ sở trực tiếp được khởi tạo bởi một danh sách khởi tạo được chỉ định trong khi toàn bộ lớp Employe được khởi tạo bởi một danh sách khởi tạo không được chỉ định.


3
hoặc kết hợp : Employee e1{ { .name{"John"}, .surname{"Wick"}, .age{40} }, 50000 };.
Jarod42

@ Jarod42 Vâng, nó biên dịch.
Vlad từ Moscow

5

Bạn có thể có một số trường có cùng tên từ các cơ sở khác nhau,

Vì vậy, về mặt logic, bạn nên cung cấp tên của cơ sở mong muốn, nhưng dường như không có cách nào để làm điều đó.

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

Ngoài ra, khởi tạo được chỉ định C ++ bị ràng buộc nhiều hơn C:

Lưu ý: khởi tạo được chỉ định không theo thứ tự, khởi tạo được chỉ định lồng nhau, trộn lẫn các khởi tạo được chỉ định và khởi tạo thường xuyên và khởi tạo được chỉ định của mảng đều được hỗ trợ trong ngôn ngữ lập trình C, nhưng không được phép trong C ++.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.