Angew's i jaggedSpire są doskonałe i odnoszą się doc ++ 11. Ic ++ 14. Ic ++ 17.
Jednak w c ++ 20, rzeczy się trochę zmieniają i przykład w PO nie będzie się już kompilować:
class C {
C() = default;
};
C p;
auto q = C();
C r{};
auto s = C{};
Jak wskazano w dwóch odpowiedziach, powodem, dla którego dwie ostatnie deklaracje działają, jest to, że Cjest to agregacja, a jest to inicjalizacja agregacji. Jednak w wyniku P1008 (przy użyciu motywującego przykładu nie różniącego się zbytnio od PO), definicja zagregowanych zmian w C ++ 20 do, z [dcl.init.aggr] / 1 :
Agregat to tablica lub klasa ([klasa]) z
- brak konstruktorów zadeklarowanych przez użytkownika lub dziedziczonych ([class.ctor]),
- brak prywatnych lub chronionych bezpośrednich niestatycznych składowych danych ([class.access]),
- brak funkcji wirtualnych ([class.virtual]) i
- brak wirtualnych, prywatnych lub chronionych klas bazowych ([class.mi]).
Podkreśl moje. Teraz wymaganiem jest brak konstruktorów zadeklarowanych przez użytkownika , podczas gdy kiedyś (jak obaj użytkownicy cytują w swoich odpowiedziach i można je przeglądać historycznie dla C ++ 11 , C ++ 14 i C ++ 17 ) nie było konstruktorów dostarczonych przez użytkownika . Domyślny konstruktor dla Cjest zadeklarowany przez użytkownika, ale nie jest dostarczany przez użytkownika, dlatego przestaje być agregacją w C ++ 20.
Oto kolejny przykład ilustrujący zagregowane zmiany:
class A { protected: A() { }; };
struct B : A { B() = default; };
auto x = B{};
Bnie był agregatem w C ++ 11 ani C ++ 14, ponieważ ma klasę bazową. W rezultacie B{}po prostu wywołuje domyślny konstruktor (zadeklarowany przez użytkownika, ale nie dostarczony przez użytkownika), który ma dostęp do Achronionego konstruktora domyślnego.
W C ++ 17, w wyniku P0017 , agregaty zostały rozszerzone o klasy bazowe. Bjest agregatem w C ++ 17, co oznacza, że B{}jest to inicjalizacja agregatu, która musi zainicjować wszystkie podobiekty - w tym Apodobiekt. Ale ponieważ Adomyślny konstruktor jest chroniony, nie mamy do niego dostępu, więc ta inicjalizacja jest źle sformułowana.
W C ++ 20, z powodu Bkonstruktora zadeklarowanego przez użytkownika, ponownie przestaje być agregatem, więc B{}powraca do wywoływania domyślnego konstruktora i jest to ponownie dobrze sformułowana inicjalizacja.
C c{};inicjalizacja agregacji, więc żaden konstruktor nie jest wywoływany?