Замена вектора с помощью списка инициализаторов
i имеет std::vector<std::vector<double>>
и хотел бы добавить некоторые элементы в конце этого, так что это было мое испытание:
std::vector<std::vector<double> > vec;
vec.emplace_back({0,0});
но это не скомпилируется, тогда как следующее:
std::vector<double> vector({0,0});
Почему emplace_back не может создать элемент в этой позиции? Или что я делаю неправильно?
Спасибо за вашу помощь.
Ответы
Ответ 1
Вычисление шаблона не может угадать, что заключенный в скобки список инициализации должен быть вектором. Вы должны быть явными:
vec.emplace_back(std::vector<double>{0.,0.});
Обратите внимание, что это создает вектор, а затем перемещает его в новый элемент с помощью std::vector
конструктор перемещения копии. Так что в данном конкретном случае он не имеет преимущества перед push_back()
. Ответ @TimKuipers показывает способ обойти эту проблему.
Ответ 2
В предыдущем ответе вы можете получить код для компиляции, когда вы конструируете вектор в строке и замените это.
Это означает, однако, что вы вызываете конструктор move на временном векторе, что означает, что вы не создаете вектор на месте, тогда как вся причина использования emplace_back
, а не push_back
.
Вместо этого вы должны перечислить список инициализаторов в initializer_list
, например:
#include <vector>
#include <initializer_list>
int main()
{
std::vector<std::vector<int>> vec;
vec.emplace_back((std::initializer_list<int>){1,2});
}
Ответ 3
Конструктор std::vector<double>
может использовать фигурный список int
для своего конструктора std::vector<double>(std::initializer_list<double>)
.
emplace_back()
не может emplace_back()
элемент из выражения фигурных скобок, потому что это шаблон, который использует идеальную пересылку. Стандарт запрещает компилятору выводить тип {0,0}
, поэтому std::vector<double>::emplace_back<std::initializer_list<double>>(std::initializer_list<double>)
не компилируется для emplace_back({})
.
Другой ответ указывает, что emplace_back
может быть скомпилирован для аргумента типа std::initializer_list<T>
если он не должен выводить тип непосредственно из выражения {}
. В качестве альтернативы приведению аргумента к emplace_back
, вы можете сначала emplace_back
аргумент. Как указано в пункте 30 Мейерса ("Эффективное современное" C++), auto
разрешается выводить тип выражения фигурной скобки, а при совершенной пересылке - тип объекта, тип которого был выведен auto
.
std::vector<std::vector<double> > vec;
auto int_list = {0, 0}; // int_list is type std::initializer_list<int>
vec.emplace_back(int_list); // instantiates vec.emplace_back<std::initializer_list<int>>
emplace_back
добавляет элемент в vec
, вызывая std::vector<double>(std::forward<std::initializer_list<int>>(int_list))
, что вызывает std::vector<double>(std::initializer_list<double>)
конструктор и элементы int_list
конвертируются.