С помощью простого struct, например

struct Foo { int i; };

Я могу создать новый экземпляр, используя список инициализаторов; не нужно писать конструктор:

Foo foo { 314 };

Если я сейчас добавлю конструктор перемещения

struct Bar
{
    int i;
    Bar(Bar&& other) { i = other.i; }
};

Инициализатор больше не работает, и мне тоже нужно добавить конструктор:

Bar(int i) : i(i) {}

Я предполагаю, что это поведение отчасти связано с этим ответом (для определяемый пользователем конструктор перемещения отключает неявный конструктор копирования?), но более подробная информация будет хороший.

Изменить: как указано в ответах, это связано с добавлением конструктора. Что, в свою очередь, могло бы создать некоторую несогласованность, если бы я добавил только оператор перемещения:

struct Baz
{
    int i;

    Baz& operator=(Baz&& other)
    {
        this->i = other.i;
        return *this;
    }
};

Инициализатор снова работает, хотя и с немного другим синтаксисом для "перемещения" (да, это фактически конструкция по умолчанию и назначение перемещения; но конечный результат кажется примерно таким же):

Baz baz{ 3141 };
Baz b;
b = std::move(baz);
5
Ðаn 25 Ноя 2016 в 18:15

3 ответа

Лучший ответ

Конструктор перемещения отключает не конструкцию списка инициализаторов (которой изначально не было), а совокупную конструкцию . И по уважительной причине: добавляя настраиваемый конструктор, мы точно указываем компилятору, что класс в не агрегат , что необходимо что-то другое, а не просто работать с каждым из его членов один за другим.

Для агрегата конструктор копирования и перемещения по умолчанию будет работать хорошо, даже если переменные-члены имеют нетривиальные типы. Конструкция копии будет автоматически удалена, если она не может быть делегирована им, оставляя конструкцию перемещения пригодной для использования:

struct A { // non-copyable
  int a;
  int b;
  A(int a_, int b_): a(a_), b(b_) { std::cout << "A(int,int)\n"; }
  A() { std::cout << "A()\n"; }
  A(const A&) = delete;
  A(A&&) { std::cout << "A(A&&)\n"; }
};

struct B {
  A a;
};

int main() {
  B b1{{1,2}}; // OK: aggregate
  B b2{std::move(b1)}; // OK: calls A::A(A&&)
  //B b3{b1}; // error: B::B(const B&) auto-deleted
}

Однако, если вы хотите удалить конструкцию копии по какой-либо другой причине и оставить остальные по умолчанию, просто укажите это явно:

struct A { // copyable
  int a;
  int b;
  A(int a_, int b_): a(a_), b(b_) { std::cout << "A(int,int)\n"; }
  A() { std::cout << "A()\n"; }
  A(const A&) { std::cout << "A(const A&)\n"; }
  A(A&&) { std::cout << "A(A&&)\n"; }
};

struct B { // non-copyable
  A a;
  B() = default;
  B(const B&) = delete;
  B(B&&) = default;
};

int main() {
  B b1{{1,2}}; // OK: still an aggregate
  B b2{std::move(b1)}; // delegates to A::A(A&&)
  //B b3{b1}; // error
}
4
The Vee 25 Ноя 2016 в 16:08

Если конструкторов нет, этот синтаксис является агрегированной инициализацией, поскольку эта структура является совокупный .

Когда добавляется конструктор, эта структура больше не является агрегатом , нельзя использовать агрегатную инициализацию . Точные правила перечислены в инициализации списка, соответствующие из них:

Эффекты инициализации списка объекта типа T:

  • В противном случае, если T является агрегатным типом, выполняется агрегатная инициализация.
  • В противном случае конструкторы T рассматриваются в два этапа: ...
7
Community 20 Июн 2020 в 09:12

Поскольку вы используете агрегированную инициализацию, в которой говорится:

Агрегатная инициализация - это форма инициализации списка, которая инициализирует агрегаты. Агрегат - это один из следующих типов: тип массива, тип класса (обычно структура или объединение), который имеет

  • нет частных или защищенных нестатических элементов данных
  • не предоставлено пользователем, унаследованные или явные (начиная с C ++ 17) конструкторы (явно разрешены конструкторы по умолчанию или удаленные) (начиная с C ++ 11)
  • нет виртуальные, частные или защищенные (начиная с C ++ 17) базовые классы
  • нет виртуального функции-члены

Пункт 2 делает ваше дело провальным.

4
Hatted Rooster 25 Ноя 2016 в 15:28