Відповіді Енджу та нерівного шпиля відмінні і стосуютьсяc ++ 11. Іc ++ 14. Іc ++ 17.
Однак у c ++ 20, речі трохи змінюються, і приклад в OP більше не компілюється:
class C {
C() = default;
};
C p;
auto q = C();
C r{};
auto s = C{};
Як зазначено у двох відповідях, причина того, що два останні оголошення працюють, полягає в тому, що C
є сукупністю, а це ініціалізацією сукупності. Однак, як результат P1008 (використовуючи мотивуючий приклад, який не надто відрізняється від OP), визначення сукупності змінюється в C ++ 20 до, від [dcl.init.aggr] / 1 :
Агрегат - це масив або клас ([клас]) з
- відсутність оголошених користувачем або успадкованих конструкторів ([class.ctor]),
- відсутність приватних або захищених прямих нестатичних членів даних ([class.access]),
- відсутність віртуальних функцій ([class.virtual]), і
- відсутність віртуальних, приватних або захищених базових класів ([class.mi]).
Акцент мій. Зараз вимога не полягає в заявлених користувачем конструкторах, тоді як раніше (як цитують обидва користувачі у своїх відповідях і їх можна історично переглянути для C ++ 11 , C ++ 14 та C ++ 17 ) не було наданих користувачем конструкторів . Конструктор за замовчуванням C
оголошений користувачем, але не наданий користувачем, і, отже, перестає бути сукупністю в C ++ 20.
Ось ще один наочний приклад сукупних змін:
class A { protected: A() { }; };
struct B : A { B() = default; };
auto x = B{};
B
не був сукупністю в C ++ 11 або C ++ 14, оскільки він має базовий клас. В результаті B{}
просто викликає конструктор за замовчуванням (оголошений користувачем, але не наданий користувачем), який має доступ до A
захищеного конструктора за замовчуванням.
У C ++ 17, як результат P0017 , агрегати були розширені для забезпечення базових класів. B
є сукупністю в C ++ 17, що означає, що B{}
це ініціалізація агрегату, яка повинна ініціалізувати всі суб'єкти - включаючи A
суб'єкт. Але оскільки A
конструктор за замовчуванням захищений, ми не маємо до нього доступу, тому ця ініціалізація неправильно сформована.
У C ++ 20 через B
конструктор, оголошений користувачем, він знову перестає бути сукупністю, тому B{}
повертається до виклику конструктора за замовчуванням, і це знову добре сформована ініціалізація.
C c{};
сукупна ініціалізація не викликає жодного конструктора?