Почему этот std :: vector :: emplace_back терпит неудачу?

Я сталкиваюсь с ошибкой компилятора:

попытка ссылки на удаленную функцию

#include <iostream>
#include <vector>

template <typename T>
struct Container
{
    Container() = default;
    Container(const Container& other) = delete;
    Container(T* ptr) : ptr(ptr) {}
    T* ptr;
    ~Container() { delete ptr; }

};

struct Foo { Foo(int a, int b) {} };

int main()
{
    std::vector<Container<Foo>> myvector;
    myvector.push_back(new Foo(1, 2)); // I understand why this doesn't work.
    myvector.emplace_back((new Foo(1, 2))); // I don't understand why this fails

}

Я понимаю, почему он говорит о попытке ссылаться на удаленный конструктор, когда я делаю std::vector::push_back(), потому что это делает копию и требует вызова конструктора копирования, который я удалил.

Но std::vector::emplace_back() должен принимать аргументы конструктора того типа, который он имеет. Когда я вернусь назад, я даю ему указатель на Foo, и это должно быть перенаправлено в конструктор Container::Container(T* ptr).

Что мне не хватает?

Ответ 1

Объявление конструктора копии, заданного пользователем, не будет определять неявный конструктор перемещения; T должен либо иметь конструктор копирования, либо конструктор перемещения для push_back или emplace_back* объекта в std::vector<T>.

В документах см. Требования к T для создания std::vector<T>. (Здесь нет ограничений, читайте дальше).

Требования, предъявляемые к элементам, зависят от фактических операций, выполняемых на контейнере. Как правило, требуется, чтобы тип элемента отвечал требованиям Erasable, но многие функции-члены предъявляют более строгие требования. Этот контейнер (но не его члены) может быть создан с неполным типом элемента, если распределитель удовлетворяет требованиям полноты распределителя.

Из std::vector<...>::push_back:

Требования к типу

  • T должен соответствовать требованиям CopyInsertable, чтобы использовать перегрузку (1).
  • T должен соответствовать требованиям MoveInsertable, чтобы использовать перегрузку (2).

Из std::vector<...>::emplace_back:

Требования к типу

  • T (тип элемента контейнера) должен соответствовать требованиям MoveInsertable и EmplaceConstructible.

Однако для emplace_back ваш код будет удовлетворять критериям EmplaceConstructible, потому что могут произойти перераспределения, вы также должны выполнить MoveInsertable.