通常使用元组来简化传递可变数量的项目(在这种情况下,将参数转发到emplace_back),使用a little technique 将元组解包回来。因此,可以通过要求用户在有意义的地方使用元组工厂函数(std::make_tuple、std::tie、std::forward_as_tuple 之一)来编写 back_emplacer 实用程序:
#include <type_traits>
#include <tuple>
// Reusable utilites
template<typename T>
using RemoveReference = typename std::remove_reference<T>::type;
template<typename T>
using Bare = typename std::remove_cv<RemoveReference<T>>::type;
template<typename Out, typename In>
using WithValueCategoryOf = typename std::conditional<
std::is_lvalue_reference<In>::value
, typename std::add_lvalue_reference<Out>::type
, typename std::conditional<
std::is_rvalue_reference<Out>::value
, typename std::add_rvalue_reference<Out>::type
, Out
>::type
>::type;
template<int N, typename Tuple>
using TupleElement = WithValueCategoryOf<
typename std::tuple_element<N, RemoveReference<Tuple>>::type
, Tuple
>;
// Utilities to unpack a tuple
template<int... N>
struct indices {
using next = indices<N..., sizeof...(N)>;
};
template<int N>
struct build_indices {
using type = typename build_indices<N - 1>::type::next;
};
template<>
struct build_indices<0> {
using type = indices<>;
};
template<typename Tuple>
constexpr
typename build_indices<std::tuple_size<Bare<Tuple>>::value>::type
make_indices() { return {}; }
template<typename Container>
class back_emplace_iterator {
public:
explicit back_emplace_iterator(Container& container)
: container(&container)
{}
template<
typename Tuple
// It's important that a member like operator= be constrained
// in this case the constraint is delegated to emplace,
// where it can more easily be expressed (by expanding the tuple)
, typename = decltype( emplace(std::declval<Tuple>(), make_indices<Tuple>()) )
>
back_emplace_iterator& operator=(Tuple&& tuple)
{
emplace(*container, std::forward<Tuple>(tuple), make_indices<Tuple>());
return *this;
}
template<
typename Tuple
, int... Indices
, typename std::enable_if<
std::is_constructible<
typename Container::value_type
, TupleElement<Indices, Tuple>...
>::value
, int
>::type...
>
void emplace(Tuple&& tuple, indices<Indices...>)
{
using std::get;
container->emplace_back(get<Indices>(std::forward<Tuple>(tuple))...);
}
// Mimic interface of std::back_insert_iterator
back_emplace_iterator& operator*() { return *this; }
back_emplace_iterator& operator++() { return *this; }
back_emplace_iterator operator++(int) { return *this; }
private:
Container* container;
};
template<typename Container>
back_emplace_iterator<Container> back_emplacer(Container& c)
{ return back_emplace_iterator<Container> { c }; }
代码演示是available。在你的情况下,你想打电话给std::fill_n(back_emplacer(v), 10, std::forward_as_tuple(1, 1.0));(std::make_tuple 也是可以接受的)。您还希望使用常用的迭代器来完成该功能——我为此推荐 Boost.Iterators。
我必须真正强调的是,当与std::fill_n 一起使用时,这样的实用程序不会带来太多好处。在您的情况下,它将保存临时Foo 的构造,以支持引用元组(如果您要使用std::make_tuple,则为值元组)。我把它留给读者去寻找back_emplacer 有用的其他算法。