可变参数模板函数来连接std :: vector容器 [英] variadic template function to concatenate std::vector containers

查看:265
本文介绍了可变参数模板函数来连接std :: vector容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在学习模板参数包时,我想写一个聪明,简单的函数来有效地将两个或多个 std :: vector 容器附加在一起。

While learning about template parameter packs, I'm trying to write a clever, simple function to efficiently append two or more std::vector containers together.

以下是两种初始解决方案。

Below are two initial solutions.

版本1是优雅的,但是容易出错,因为它依赖于扩展期间的副作用

Version 1 is elegant but buggy, as it relies on side-effects during the expansion of the parameter pack, and the order of evaluation is undefined.

版本2的工作原理,但依赖于一个需要两种情况的帮助函数。 Yuck。

Version 2 works, but relies on a helper function that requires two cases. Yuck.

你能看到你能否想出一个更简单的解决方案?
(为了效率,向量数据不应该被多次复制。)

Can you see if you can come up with a simpler solution? (For efficiency, the vector data should not be copied more than once.)

#include <vector>
#include <iostream>

// Append all elements of v2 to the end of v1.
template<typename T>
void append_to_vector(std::vector<T>& v1, const std::vector<T>& v2) {
    for (auto& e : v2) v1.push_back(e);
}

// Expand a template parameter pack for side effects.
template<typename... A> void ignore_all(const A&...) { }

// Version 1: Concatenate two or more std::vector<> containers into one.
// Nicely simple, but buggy as the order of evaluation is undefined.
template<typename T, typename... A>
std::vector<T> concat1(std::vector<T> v1, const A&... vr) {
    // Function append_to_vector() returns void, so I enclose it in (..., 1).
    ignore_all((append_to_vector(v1, vr), 1)...);
    // In fact, the evaluation order is right-to-left in gcc and MSVC.
    return v1;
}

// Version 2:
// It works but looks ugly.
template<typename T, typename... A>
void concat2_aux(std::vector<T>& v1, const std::vector<T>& v2) {
    append_to_vector(v1, v2);
}

template<typename T, typename... A>
void concat2_aux(std::vector<T>& v1, const std::vector<T>& v2, const A&... vr) {
    append_to_vector(v1, v2);
    concat2_aux(v1, vr...);
}

template<typename T, typename... A>
std::vector<T> concat2(std::vector<T> v1, const A&... vr) {
    concat2_aux(v1, vr...);
    return v1;
}

int main() {
    const std::vector<int> v1 { 1, 2, 3 };
    const std::vector<int> v2 { 4 };
    const std::vector<int> v3 { 5, 6 };
    for (int i : concat1(v1, v2, v3)) std::cerr << " " << i;
    std::cerr << "\n";          // gcc output is:  1 2 3 5 6 4
    for (int i : concat2(v1, v2, v3)) std::cerr << " " << i;
    std::cerr << "\n";          // gcc output is:  1 2 3 4 5 6
}


推荐答案

帮助类型:我不喜欢使用 int

A helper type: I dislike using intfor it.

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

添加尺寸:'

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

Concat。要忽略的返回类型:

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.

这篇关于可变参数模板函数来连接std :: vector容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆