variadic template function to concatenate std::vector containers

走远了吗. 提交于 2019-12-03 21:43:19

A helper type: I dislike using intfor it.

struct do_in_order { template<class T>do_in_order(T&&){}};

Add up sizes:'

template<class V>
std::size_t sum_size( std::size_t& s, V&& v ) {return s+= v.size(); }

Concat. Returns type to be ignored:

template<class V>
do_in_order concat_helper( V& lhs, V const& rhs ) { lhs.insert( lhs.end(), rhs.begin(), rhs.end() ); return {}; }

Micro optimization, and lets you concat vectors of move only types:

template<class V>
do_in_order concat_helper( V& lhs, V && rhs ) { lhs.insert( lhs.end(), std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end()) ); return{}; }

actual function. Above stuff should be in a details namespace:

template< typename T, typename A, typename... Vs >
std::vector<T,A> concat( std::vector<T,A> lhs, Vs&&...vs ){
  std::size s=lhs.size();
  do_in_order _0[]={ sum_size(s,vs)..., 0 };
  lhs.reserve(s);
  do_in_order _1[]={ concat_helper( lhs, std::forward<Vs>(vs) )..., 0 };
  return std::move(lhs); // rvo blocked
}

apologies for any typos.

Hugues

There is a related answer on concatenation of strings: https://stackoverflow.com/a/21806609/1190077 . Adapted here, it looks like:

template<typename T, typename... A>
std::vector<T> concat_version3(std::vector<T> v1, const A&... vr) {
    int unpack[] { (append_to_vector(v1, vr), 0)... };
    (void(unpack));
    return v1;
}

This seems to work!

However, is the evaluation order of the template parameter pack now well-defined, or is it by accident that the compiler did the right thing?

Hugues

The answer by Yakk (https://stackoverflow.com/a/23439527/1190077) works well.

Here is a polished version, incorporating my improvement to do_in_order and removing the sum_size external function:

// Nice syntax to allow in-order expansion of parameter packs.
struct do_in_order {
    template<typename T> do_in_order(std::initializer_list<T>&&) { }
};

namespace details {
template<typename V> void concat_helper(V& l, const V& r) {
    l.insert(l.end(), r.begin(), r.end());
}
template<class V> void concat_helper(V& l, V&& r) {
    l.insert(l.end(), std::make_move_iterator(r.begin()),
             std::make_move_iterator(r.end()));
}
} // namespace details

template<typename T, typename... A>
std::vector<T> concat(std::vector<T> v1, A&&... vr) {
    std::size_t s = v1.size();
    do_in_order { s += vr.size() ... };
    v1.reserve(s);
    do_in_order { (details::concat_helper(v1, std::forward<A>(vr)), 0)... };
    return std::move(v1);   // rvo blocked
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!