考虑以下程序:
#include <string>
#include <vector>
using namespace std;
struct T
{
int a;
double b;
string c;
};
vector<T> V;
int main()
{
V.emplace_back(42, 3.14, "foo");
}
它不起作用:
$ g++ -std=gnu++11 ./test.cpp
In file included from /usr/include/c++/4.7/x86_64-linux-gnu/bits/c++allocator.h:34:0,
from /usr/include/c++/4.7/bits/allocator.h:48,
from /usr/include/c++/4.7/string:43,
from ./test.cpp:1:
/usr/include/c++/4.7/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = T; _Args = {int, double, const char (&)[4]}; _Tp = T]’:
/usr/include/c++/4.7/bits/alloc_traits.h:253:4: required from ‘static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = T; _Args = {int, double, const char (&)[4]}; _Alloc = std::allocator<T>; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]’
/usr/include/c++/4.7/bits/alloc_traits.h:390:4: required from ‘static void std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = T; _Args = {int, double, const char (&)[4]}; _Alloc = std::allocator<T>]’
/usr/include/c++/4.7/bits/vector.tcc:97:6: required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int, double, const char (&)[4]}; _Tp = T; _Alloc = std::allocator<T>]’
./test.cpp:17:32: required from here
/usr/include/c++/4.7/ext/new_allocator.h:110:4: error: no matching function for call to ‘T::T(int, double, const char [4])’
/usr/include/c++/4.7/ext/new_allocator.h:110:4: note: candidates are:
./test.cpp:6:8: note: T::T()
./test.cpp:6:8: note: candidate expects 0 arguments, 3 provided
./test.cpp:6:8: note: T::T(const T&)
./test.cpp:6:8: note: candidate expects 1 argument, 3 provided
./test.cpp:6:8: note: T::T(T&&)
./test.cpp:6:8: note: candidate expects 1 argument, 3 provided
正确的方法是什么?为什么?
(Also尝试了单大括号和双大括号)
8条答案
按热度按时间eqzww0vc1#
当然,这不是答案,但它显示了元组的一个有趣的特性:
3mpgtkmj2#
如果你不想(或者不能)添加构造函数,可以为T专门化分配器(或者创建你自己的分配器)。
注:上面显示的成员函数结构不能用clang3.1编译(对不起,我不知道为什么)。如果你要用clang3.1(或其他原因),请尝试下一个。
myss37ts3#
23.2.1/13中似乎涵盖了这一点。
首先,定义:
给定容器类型X具有与A相同的分配器类型和与T相同的值类型,并且给定类型A的左值m、类型T* 的指针p、类型T的表达式v和类型T的右值rv,定义以下术语。
那么,是什么使它可以建造呢?
T is EmplaceConstructable into X from args,对于零个或多个参数args,意味着下面的表达式是格式良好的:分配器特征::构造(m,p,args);
最后是关于构造调用的默认实现的说明:
注意:容器调用allocator_traits::construct(m,p,args)来使用args在p构造一个元素。std::allocator中的默认构造将调用::new((void*)p)T(args),但专用分配器可能会选择不同的定义。
这很大程度上告诉我们,对于一个默认的(可能是唯一的)分配器方案,你 * 必须 * 定义一个构造函数,该构造函数具有适当数量的参数,用于你试图将构造函数放置到容器中的东西。
rsaldnfx4#
emplace_back在c++17和更新版本中返回一个引用,所以你可以这样做...
bfnvny8b5#
你必须为你的类型
T
定义一个构造函数,因为它包含了一个std::string
,这不是微不足道的。此外,最好定义(可能是默认的)move ctor/assign(因为您有一个可移动的
std::string
作为成员)--这将有助于更有效地移动您的T
...或者,按照neighboug response中的建议,使用
T{...}
调用重载的emplace_back()
......一切取决于您的典型用例......mpgws1up6#
您可以创建
struct T
示例,然后将其移动到向量:mzaanser7#
你需要为类显式定义一个ctor:
使用
emplace_back
的目的是避免创建临时对象,然后复制该临时对象虽然也可以创建一个临时对象,然后将其传递给emplace_back
,但它会失败(至少大部分)的目的。你要做的是传递单个参数,然后让emplace_back
用这些参数调用ctor以在适当的位置创建对象。zbwhf8kr8#
对于任何来自未来的人来说,这种行为will be changed在C++20。
换句话说,即使实现内部仍将调用
T(arg0, arg1, ...)
,但它将被视为您所期望的常规T{arg0, arg1, ...}
。