initializers ที่กำหนดใน C ++ 20


25

ฉันมีคำถามเกี่ยวกับหนึ่งในคุณสมบัติ c ++ 20 ซึ่งเป็น initializers ที่กำหนด (ข้อมูลเพิ่มเติมเกี่ยวกับคุณลักษณะนี้ที่นี่ )

#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รวมได้โดยใช้ initializers ที่กำหนด

มีคนอธิบายได้ไหมทำไม


ฉันไม่ทราบว่าจะแก้ปัญหาของคุณ แต่คุณอาจไม่ได้รับมรดกที่สาธารณะที่นี่ ...struct Employee : public Person
skratchi.at


@GSerg ตกลงกัน ... ฉันไม่เคยสูญเสียความคิดว่าเพราะผมใช้publicหรือprivateทุกครั้ง ... ขอบคุณอยู่ดี
skratchi.at

คุณได้รับข้อผิดพลาดอะไร
skratchi.at

2
@ skratchi.at structสืบทอดต่อสาธารณชนเป็นค่าเริ่มต้น
idclev 463035818

คำตอบ:


15

ตามมาตรฐาน C ++ 20 (9.3.1 Aggregates. p. # 3)

(3.1) - หากรายการ initializer เป็นรายการเริ่มต้นที่กำหนดรวมจะต้องเป็นประเภทชั้นตัวระบุในแต่ละ designator จะตั้งชื่อสมาชิกข้อมูลที่ไม่คงที่โดยตรงของชั้นเรียนและองค์ประกอบเริ่มต้นอย่างชัดเจนของการรวม เป็นองค์ประกอบที่มีหรือมีสมาชิกเหล่านั้น

ดังนั้นคุณไม่สามารถใช้รายการ initializer ที่กำหนดเพื่อเริ่มต้นสมาชิกข้อมูลของคลาสฐาน

ใช้แทนการเริ่มต้นรายการปกติเช่น

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

หรือ

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

หรือ@ Jarod42ชี้ให้เห็นในความคิดเห็นที่คุณสามารถเขียน

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

ในกรณีนี้คลาสพื้นฐานโดยตรงถูกเตรียมใช้งานโดยรายการ initializer ที่กำหนดในขณะที่คลาส Employee ทั้งหมดถูกเตรียมใช้งานโดยรายการ initializer ที่ไม่ได้กำหนด


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 ++

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.