26

我有一个std::vector<std::vector<double>>并且想在它的末尾添加一些元素所以这是我的试验:

std::vector<std::vector<double> > vec;
vec.emplace_back({0,0});

但这不会编译,而以下会做:

std::vector<double> vector({0,0});

为什么emplace_back不能在这个位置构造元素?或者我做错了什么?

谢谢你的帮助。

4

3 回答 3

32

前面的答案提到,当您在行中构造向量并将其放置时,您可以获得要编译的代码。但是,这意味着您在临时向量上调用 move-constructor,这意味着您没有就地构造向量,而这就是使用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});
}
于 2016-11-16T12:14:02.617 回答
14

模板推导猜不出你的大括号括起来的初始化列表应该是一个向量。你需要明确:

vec.emplace_back(std::vector<double>{0.,0.});

请注意,这构造了一个向量,然后使用std::vector的移动复制构造函数将其移动到新元素中。所以在这种特殊情况下,它没有优势push_back()。@TimKuipers 的回答显示了解决此问题的方法。

于 2014-07-03T10:18:47.553 回答
3

这里确实存在两个问题:数值类型转换和模板参数推导。

构造std::vector<double>函数可以使用花括号列表(甚至是ints)作为其std::vector<double>(std::initializer_list<double>)构造函数。(但请注意,这std::initializer_list<int>不会隐式转换为std::initializer_list<double>

emplace_back()无法从大括号表达式构造元素,因为它是使用完美转发的模板。该标准禁止编译器推断 的类型{0,0},因此std::vector<double>::emplace_back<std::initializer_list<double>>(std::initializer_list<double>)不会为 编译emplace_back({})

其他答案指出emplace_back 可以为 type 的参数编译std::initializer_list<vector::value_type>,但不会直接从{}表达式中推断出这种类型。

作为将参数强制转换为 的替代方法emplace_back,您可以先构造参数。正如 Meyers 的第 30 条(有效的现代 C++)中所指出的,auto允许将大括号表达式的类型推断为std::initializer_list<T>,并且允许完美转发推断其类型由 推断的对象的类型auto

std::vector<std::vector<double> > vec;
auto double_list = {0., 0.}; // int_list is type std::initializer_list<int>
vec.emplace_back(double_list); // instantiates vec.emplace_back<std::initializer_list<double>&>

emplace_backvec通过调用添加一个元素std::vector<double>(std::forward<std::initializer_list<double>>(double_list)),这会触发std::vector<double>(std::initializer_list<double>)构造函数。

参考:第 17.8.2.5 节第 5.6 节表明这是一个非推导上下文,用于 17.8.2.1 第 1 项下的模板参数推导。

更新:这个答案的早期版本错误地暗示std::initializer_list<int>可以代替std::initializer_list<double>.

于 2018-08-10T14:51:17.473 回答