不能 emplace_back() 向量向量上的花括号初始化器

Cannot emplace_back() a braced initializer on a vector of vectors

这与我之前提出的关于在成对向量上使用 emplace_back 的问题有些相关。

现在我的问题是关于在向量的向量上使用 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) 将一个由 2 组成的大小为 3 的向量插入到矩阵中吗?

在这种情况下,{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 的构造函数。请注意,这里没有创建 "extra" initializer_list 对象。在使用支撑初始化创建任何向量时,无论如何都会创建这样一个对象:

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

这也会创建一个 initializer_list 对象,因为这是向量构造函数所采用的对象。

至于为什么 emplace_back(2,3) 有效,那是因为有一个向量构造函数需要一个大小和一个值。