C ++ 11引入了emplace
函数来在序列中就地构造元素。这是insert
的补充,它复制或移动元素。
但是,在insert
的几个重载中,只有单个元素插入版本
即
iterator insert( const_iterator p, T const& x);
iterator insert( const_iterator p, T&& x );
有一个emplace
版本,
template< class... Args >
iterator emplace(const_iterator p, Args&&... x);
是否有任何理由,不允许使用n
就地构建emplace
元素?
虽然过载如此,
template< class... Args >
iterator emplace(const_iterator p,size_type n,Args&&... x);
就像对应的insert
iterator insert(const_iterator p,size_type n,const_reference x);
可能与其他重载冲突,将构造函数参数作为tuple
,或使用某些特殊标记(如in_place_t
)来消除歧义。
修改
emplace_n
的建议函数vector
可能具有下面给出的行为
template<class... Args>
iterator emplace_n(const_iterator p,size_type n,Args&&... x)
{
size_type const offset = p - begin();
if(capacity() < size()+n)
{
vector<T> v;
v.reserve(size()+n);
v.assign(make_move_iterator(begin(),make_move_iterator(end());
swap(*this,v);
}
auto const sz = size();
for(auto c = 0; c != n ; ++c)
{
emplace_back(x...); //can do forward only if n == 1
}
rotate(begin()+offset,begin()+sz,end());
return iterator{begin() + offset};
}
答案 0 :(得分:2)
问题是没有简单的方法来确定一个元素的参数何时结束以及下一个元素的参数何时开始。你可以通过tuple
传递参数,就像pair
的分段构造函数一样,最后得到一个像这样的辅助函数:
template<int... Is>
struct index_seq { };
template<int N, int... Is>
struct make_index_seq : make_index_seq<N - 1, N - 1, Is...> { };
template<int... Is>
struct make_index_seq<0, Is...> : index_seq<Is...> { };
template<class Cont, class Tup, int... Is>
void emplace_back_impl(Cont& c, Tup&& tup, index_seq<Is...>)
{
using std::get;
c.emplace_back(get<Is>(std::forward<Tup>(tup))...);
}
template<class Cont, class... Tups>
void emplace_multiple(Cont& c, Tups&&... tups)
{
int const unpack[]{
0, ((emplace_back_impl)(c, std::forward<Tups>(tups),
make_index_seq<
std::tuple_size<typename std::remove_reference<Tups>::type>{}
>()), 0)...
};
static_cast<void>(unpack);
}
然后你可以使用emplace_multiple
函数来放置多个元素:
std::vector<std::string> xs;
emplace_multiple(xs, std::make_tuple("Hello, world!"), std::make_tuple(10, 'a'));
请注意,这使用emplace_back
。如果您没有提前预留足够的空间,使用emplace
加上迭代器来标记插入位置是危险的。这是因为emplace
和emplace_back
可以使迭代器无效(至少对于vector
s),然后该函数不知道如何将新的迭代器添加到您想要的位置。 / p>
答案 1 :(得分:1)
让我们在给定位置调用建议的函数emplace_n
,以某种方式安置n
元素。对于emplace
,显然必须转发所有参数(迭代器除外)以构造必须放置的一个元素。现在考虑只在这个位置“安置”两个要素:
vector<X> vx;
vector<X>::const_iterator it = ... ;
vx.emplace_2(it, a1, a2, a3, a4, a5);
现在,哪个参数将用于构造第一个,构造第二个元素?库有几种组合无法轻易区分。等效的“单一阵地”可能是:
auto it2 = vx.emplace_2(it);
vx.emplace(it2, a1, a2, a3, a4, a5);
//or
auto it2 = vx.emplace_2(it, a1);
vx.emplace(it2, a2, a3, a4, a5);
//or
auto it2 = vx.emplace_2(it, a1, a2);
vx.emplace(it2, a3, a4, a5);
等。你明白了。对于n> 2,它变得更加复杂。
这就是为什么多个元素没有简单的“安置”的原因。但可以使用某种emplacer-iterator和std::transform
或类似的算法,用于手持式版本pf multiple-emplace。