簡體   English   中英

用於連接std :: vector容器的可變參數模板函數

[英]variadic template function to concatenate std::vector containers

在學習模板參數包時,我正在嘗試編寫一個聰明,簡單的函數來有效地將兩個或多個std::vector容器附加在一起。

以下是兩個初始解決方案。

版本1優雅但有缺陷,因為它在參數包的擴展期間依賴於副作用,並且評估的順序是未定義的。

版本2有效,但依賴於需要兩種情況的輔助函數。 呸。

你能看出你是否能想出一個更簡單的解決方案嗎? (為了提高效率,不應多次復制矢量數據。)

#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

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(); }

的毗連。 返回要忽略的類型:

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

微優化,並允許您連接僅移動類型的向量:

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{}; }

實際功能。 以上內容應該在詳細信息命名空間中:

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
}

為任何錯別字道歉。

有關字符串連接的相關答案: https//stackoverflow.com/a/21806609/1190077 在這里改編,它看起來像:

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;
}

這似乎工作!

但是,模板參數包的評估順序現在定義得很好,還是編譯器做了正確的事情是偶然的?

Yakk( https://stackoverflow.com/a/23439527/1190077 )的答案很有效。

這是一個精致的版本,將我的改進結合到do_in_order並刪除sum_size外部函數:

// 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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM