如何将 std::vector::emplace_back 与 vector<int><vector> 一起使用?
How do I use std::vector::emplace_back with vector<vector<int>>?
vector<vector<int>> res;
res.emplace_back({1,2}); // change to res.push_back({1,2}); would work
这给了我错误:
main.cpp:61:25: error: no matching function for call to ‘std::vector<std::vector<int> >::emplace_back(<brace-enclosed initializer list>)’
main.cpp:61:25: note: candidate is:
In file included from /usr/include/c++/4.7/vector:70:0,
from /usr/include/c++/4.7/bits/random.h:34,
from /usr/include/c++/4.7/random:50,
from /usr/include/c++/4.7/bits/stl_algo.h:67,
from /usr/include/c++/4.7/algorithm:63,
from miscalgoc.hpp:1,
from main.cpp:1:
/usr/include/c++/4.7/bits/vector.tcc:92:7: note: void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = std::vector<int>; _Alloc = std::allocator<std::vector<int> >]
我该如何完成这项工作?另外,为什么这里需要分配器?
问题是函数模板参数不会从大括号的初始化列表中推断出std::initializer_list
(如 { 1, 2 }
(。
例:
#include <initializer_list>
#include <type_traits>
template<typename T>
void func(T arg) {
}
int main() {
auto init_list = {1, 2}; // This works because of a special rule
static_assert(std::is_same<decltype(init_list), std::initializer_list<int>>::value, "not same");
func(std::initializer_list<int>{1, 2}); // Ok. Has explicit type.
func({1, 2}); // This doesn't because there's no rule for function
// template argument to deduce std::initializer_list
// in this form.
}
现场示例
std::vector::emplace_back()
是一个函数模板,其参数被推导。所以{1, 2}
传递它是行不通的,因为它无法推断它。为其放置显式类型
res.emplace_back(std::initializer_list<int>{1,2});
会让它工作。
现场示例
@Mark的答案非常正确。现在让我们考虑一个更实际的案例。经过一些适当的操作后,您已经用vector<int>
收集了一些数据,并想将其推送到vector<vector<int>>
:
std::vector<std::vector<int>> res;
for (int i = 0; i < 10000; ++i) {
//
// do something
//
std::vector<int> v(10000, 0); // data acquired
res.push_back(v);
}
这不像分配你已经知道的值。利用std::initializer_list
可能不再是解决方案。在这种情况下,您可以使用std::move
(以及emplace_back
或push_back
是可以接受的(
for (int i = 0; i < 10000; ++i) {
std::vector<int> v(10000, 0); // will become empty afterward
res.emplace_back(std::move(v)); // can be replaced by
// res.push_back(std::move(v));
}
性能或多或少有所提高。您仍然可以从 xvalue 移动插入的概念中受益,即通过移动构造函数而不是复制来构造对象。
更新
res.push_back(move(v))
工作的原因是因为它们在 C++11 之后重载了方法std::vector::push_back(value_type&& val)
。它是为了故意支持右值引用而制作的。
查看vector::emplace_back
的文档。 emplace_back
尝试在向量中创建新元素,方法是使用传入的参数调用新元素的构造函数。 所以基本上,当你调用 emplace_back({1,2})
时,它试图将{1,2}
传递给构造函数,但由于res
是整数向量的向量,它正在查看向量构造函数,其中没有一个可以采用大括号括起来的初始值设定项列表。
另外,请查看vector::push_back
的文档。 调用 push_back
时,它会创建一个默认对象(在本例中为 ints 向量(并将值复制到其中。 我猜push_back({1,2})
起作用的原因是大括号括起来的初始值设定项列表创建了一个值类型,push_back
接受该值类型。
虽然这个问题目前得到了很好的回答,但我想详细说明为什么push_back
在这种情况下有效。
从这个cpp首选项页面,我们看到
std::initializer_list 对象在以下情况下自动构造:
- 大括号初始化列表用于列表初始化对象,其中相应的构造函数接受 std::initializer_list参数
大- 括号初始化列表用作 的右操作数赋值或作为函数调用参数,以及相应的赋值运算符/函数接受 std::initializer_list参数
- 大括号初始化列表绑定到 auto,包括在远程循环。
- 不是我们的情况。
bush_back
本身不接受initializer_list
,但它接受T
。 在我们的例子中T
是std::vector<int>
.所以2。也不适合。
这个list initialize
方法列表提到了这一点,其中包括:
函数 ({ arg1, arg2, ... }(
所以,把所有东西放在一起,你称之为接受std::vector<int>
push_back
braced-init-list
。 std::vector
可以用它list-initialized
,因此构造向量并传递给push_back
(好吧,引用它(。
emplace_back
不适用于braced-init-list
,因为它不接受类型 T
的参数(在我们的例子中std::vector<int>
(。
你可以尝试这样的事情:
#include <iostream>
#include <initializer_list>
struct V {
int i;
int j;
V(int i, int j) {
std::cout << "i j constructorn";
}
V(std::initializer_list<int> il) {
std::cout << "init list constructorn";
}
};
void
test_f(const V &v) {
std::cout << "test_f calledn";
}
int main(void) {
test_f( {1, 2, 3} );
return 0;
}
输出将是:
init list constructor
test_f called
vector
res.emplace_back({1,2}(;
默认类型检测和转换仅发生一次。在它的用例中,它不会工作两次。 要做到这一点,您需要两个扣除额。
-
{1,2} -> 推断容器是整数的initializer_list。
-
res.emplace_back( any_initializer_list_of_ints ( -> 这里,因为成员元素类型已知是整数的向量,并且整数的初始值设定项列表可用于构造整数向量,因此initializer_list需要转换为向量。
编译器不会在同一位置推导和转换两次。所以这永远不会奏效。
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中用vector填充一个简单的动态数组
- vector.resize()中的分配错误
- 使用std::vector的OpenCL矩阵乘法
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 在某些循环内使用vector.push_back时出现分段错误
- 当vector是tje全局变量时,c++中vector的内存管理
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- std::vector的包装器,使数组的结构看起来像结构的数组
- 呼叫运营商<<临时
- 为什么(-1)%vector::size()总是返回0
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 在C++中将类(带有Vector成员)保存为二进制文件
- 编译器如何区分std::vector的构造函数
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 错误:调用"std::vector<:vector<int>>::p ush_back(std::vector<std::__cxx11::basic_string<
- std::vector::reserve(未知m),我知道m<<;N(通常)并且知道N
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- C++重载<<具有typedef'd std::vector
- std::映射<>或std::vector<>在处理大型标志集时