Inisialisasi yang ditunjuk dalam C ++ 20

25

Saya punya pertanyaan tentang salah satu fitur c ++ 20, inisialisasi yang ditunjuk (info lebih lanjut tentang fitur ini di sini )

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

Kode ini dikompilasi dengan gcc 9.2.0 dan -Wall -Wextra -std=gnu++2aflag.

Seperti yang Anda lihat di atas, kedua struct, Persondan Employeemerupakan agregat tetapi inisialisasi Employeeagregat tidak mungkin menggunakan inisialisasi yang ditunjuk.

Bisakah seseorang menjelaskan mengapa?

MateuszGierczak
sumber
Saya tidak tahu apakah ini menyelesaikan masalah Anda, tetapi Anda mungkin tidak mewarisi publik di sini ...struct Employee : public Person
skratchi.at
@ skratchi.at stackoverflow.com/a/3965003/11683
GSerg
@ GS Ok, well ... Saya tidak pernah menyia-nyiakan hal itu, karena saya menggunakan publicatau privatesetiap waktu ... terima kasih
skratchi.at
apa kesalahan sebenarnya yang Anda dapatkan ??
skratchi.at
2
@ skratchi.at structmewarisi ke publik secara default
idclev 463035818

Jawaban:

15

Menurut Standar C ++ 20 (Agregat 9.3.1. Hal. 3)

(3.1) - Jika daftar penginisialisasi adalah daftar penginisialisasi yang ditunjuk, agregat harus bertipe kelas, pengidentifikasi dalam setiap penunjuk harus menyebutkan anggota data non-statis langsung dari kelas , dan elemen agregat yang diinisialisasi secara eksplisit dari agregat. adalah elemen yang, atau mengandung, anggota tersebut.

Jadi Anda tidak boleh menggunakan daftar penginisialisasi yang ditunjuk untuk menginisialisasi data anggota kelas dasar.

Gunakan inisialisasi daftar biasa seperti

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

atau

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

atau seperti yang ditunjukkan @ Jarod42 dalam komentar yang dapat Anda tulis

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

Dalam hal ini, kelas dasar langsung diinisialisasi dengan daftar penginisialisasi yang ditunjuk sementara kelas Karyawan secara keseluruhan diinisialisasi oleh daftar penginisialisasi yang tidak ditunjuk.

Vlad dari Moskow
sumber
3
atau campuran: Employee e1{ { .name{"John"}, .surname{"Wick"}, .age{40} }, 50000 };.
Jarod42
@ Jarod42 Ya, ini mengkompilasi.
Vlad dari Moskow
5

Anda mungkin memiliki beberapa bidang dengan nama yang sama dari pangkalan yang berbeda,

jadi secara logis, Anda harus memberikan nama pangkalan yang diinginkan, tetapi tampaknya tidak ada cara untuk melakukannya.

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

Selain itu inisialisasi C ++ yang ditunjuk lebih dibatasi daripada C:

Catatan: inisialisasi yang ditunjuk out-of-order, inisialisasi yang ditunjuk bersarang, campuran inisialisasi yang ditunjuk dan inisialisasi reguler, dan inisialisasi yang ditunjuk array semua didukung dalam bahasa pemrograman C, tetapi tidak diperbolehkan dalam C ++.

Jarod42
sumber