Ответы Angew и jaggedSpire превосходны и применимы к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]) с
- нет объявленных пользователем или унаследованных конструкторов ([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{};
агрегатная инициализация не вызывается без вызова конструктора?