Невозможно emplace_back () в скобках инициализатора для вектора векторов - PullRequest
3 голосов
/ 06 июня 2019

Это в некоторой степени связано с предыдущим вопросом, который я задавал относительно использования emplace_back для вектора пар. emplace_back () против push_back при вставке пары в std :: vector

Теперь мой вопрос касается использования emplace_back для вектора векторов.

Воткод, о котором я спрашиваю с комментариями

std::vector<std::vector<int>> matrix;

matrix.emplace_back({1,2,3}); //doesn't compile

matrix.emplace_back(1,2,3); //doesn't compile

matrix.push_back({1,2,3}); //works and does what is expected (insert a vector made of {1,2,3} into matrix);

matrix.emplace_back(std::vector<int>{1,2,3});   //works but 
//defeats the purpose of using emplace_back since this makes a copy
//and is thus equivalent to push_back in this case?

matrix.emplace_back(3,2) //this compiles, 
//but it seems to insert a vector of size 3 made of 2s into the matrix. 
//not actually sure why it does this

Таким образом, из этого, matrix.emplace_back(std::vector<int>{1,2,3}); кажется единственным правильным способом использовать std::vector<T>::emplace_back для вектора векторов, но это, похоже, не дает никаких преимуществсвыше push_backПравильно ли мое понимание по этому вопросу?

Кроме того, кто-то может объяснить, почему matrix.emplace_back(3,2) вставляет в матрицу вектор размера 3, состоящий из 2-х?

1 Ответ

3 голосов
/ 06 июня 2019

В этом случае {1, 2, 3} не может быть выведено до initializer_list<int> (именно этого ожидает конструктор vector<int>, который вы хотите использовать.) Так что вам нужно немного помочь:

matrix.emplace_back(initializer_list<int>{1, 2, 3});

Это не требуется при использовании push_back(). Я не знаю точных деталей, но emplace_back() - это шаблон функции, а push_back() - нет. Правила удержания для шаблонов различны (более строгие). И у инициализатора в скобках нет типа. Из-за этого у него есть свои особые правила о том, как работает вывод типов.

По сути, это:

matrix.emplace_back(vector<int>{1, 2, 3});

создает два вектора. Пустой вектор в matrix, и переданный временный. Временный перемещается в пустой вектор. Так что все не так уж и плохо.

Однако это:

matrix.emplace_back(initializer_list<int>{1, 2, 3});

Создает только один вектор, используя конструктор, который принимает initializer_list. Обратите внимание, что здесь не создается «лишний» initializer_list объект. Такой объект будет создан в любом случае при создании любого вектора с использованием фигурной инициализации:

vector<int> vec{1, 2, 3};

Это также создает initializer_list объект, потому что это то, что принимает векторный конструктор.

Что касается того, почему emplace_back(2,3) работает, это потому, что есть векторный конструктор, который принимает размер и значение.

...