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(); может быть объявлением функции. Смотрите самый неприятный разбор.

Другие вопросы по тегам