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 C
jest 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 C
jest 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{};
B
nie 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 A
chronionego konstruktora domyślnego.
W C ++ 17, w wyniku P0017 , agregaty zostały rozszerzone o klasy bazowe. B
jest agregatem w C ++ 17, co oznacza, że B{}
jest to inicjalizacja agregatu, która musi zainicjować wszystkie podobiekty - w tym A
podobiekt. Ale ponieważ A
domyślny konstruktor jest chroniony, nie mamy do niego dostępu, więc ta inicjalizacja jest źle sformułowana.
W C ++ 20, z powodu B
konstruktora 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?