C++: как выполняется построение по списку инициализации?
C++ позволяет создавать экземпляры класса, устанавливая значение открытых членов через список инициализации, как показано в примере ниже для b1
:
class B {
public:
int i;
std::string str;
};
B b1{ 42,"foo" };
B b2();
; Однако, если я предоставлю конструктор
B(int k) { }
не скомпилируется.
Итак, что происходит за капотом? Может быть, когда не предоставлен конструктор, компилятор его предоставит? Но как он может предоставить список инициализации? Я думал, что он просто предоставит "пустой" конструктор без ввода, как показано в примере для b2
, Или это обеспечивает оба?
1 ответ
Но как он может предоставить список инициализации?
Нет не будет
Обратите внимание, что для инициализации списка B b1{ 42,"foo" };
, выполняется агрегатная инициализация.
Если
T
является агрегатным типом, выполняется агрегатная инициализация.
А также B
является агрегатным типом,
Агрегат является одним из следующих типов:
array type class type (typically, struct or union), that has no private or protected non-static data members no user-provided, inherited, or explicit constructors (explicitly defaulted or deleted constructors are allowed) no virtual, private, or protected base classes no virtual member functions
Вот почему B b1{ 42,"foo" };
работает хорошо.
И если вы предоставите пользовательский конструктор, B
становится неагрегированным типом, тогда агрегатная инициализация не будет работать снова. В этом случае вы можете только инициализировать B
лайк B b1{42};
или же B b2(42);
, который будет вызывать соответствующий конструктор.
Кстати: после предоставления пользовательского конструктора (принимая один параметр) неявно объявленный конструктор по умолчанию не будет снова объявлен компилятором. Это значит B b2;
или же B b2{};
больше не будет работать
BTW2: B b2();
может быть объявлением функции. Смотрите самый неприятный разбор.