2012-05-02 77 views
8

這裏是C++一個簡單的兩集裝箱拉鍊功能:C++壓縮可變參數模板

template <typename A, typename B> 
std::list<std::pair<A, B> > simple_zip(const std::list<A> & lhs, 
             const std::list<B> & rhs) 
{ 
    std::list<std::pair<A, B> > result; 
    for (std::pair<typename std::list<A>::const_iterator, 
       typename std::list<B>::const_iterator> iter 
     = 
     std::pair<typename std::list<A>::const_iterator, 
       typename std::list<B>::const_iterator>(lhs.cbegin(), 
                 rhs.cbegin()); 
     iter.first != lhs.end() && iter.second != rhs.end(); 
     ++iter.first, ++iter.second) 
    { 
    result.push_back(std::pair<A, B>(*iter.first, *iter.second)); 
    } 
    return result; 
} 

我怎麼會這樣擴大到與可變參數模板容器的任意號碼?

我想general_zip接受listtuple一個S(每個列表可以包含不同類型的),並返回tuplelist秒。

+1

可能DUP(我仍然很享受!):http://stackoverflow.com/questions/6631782/implementing-a-variadic-zip -function-with-const-correctness – dirkgently

+8

這個驚人的長初始化語句可以被重寫爲auto iter = std :: make_pair(lhs.cbegin(),rhs.cbegin())'。你的聲明是waaaaay很久。 – mfontanini

+0

@fontanini真棒,非常感謝。 – user

回答

13

看起來這應該工作

std::list<std::tuple<>> simple_zip() { 
    return {}; 
} 

template <typename ...T> 
std::list<std::tuple<T...>> simple_zip(std::list<T>... lst) 
{ 
    std::list<std::tuple<T...>> result; 
    for (int i = 0, e = std::min({lst.size()...}); i != e; i++) { 
    result.emplace_back(std::move(lst.front())...); 
    [](...){} ((lst.pop_front(), 0)...); 
    } 
    return result; 
} 

@Potatoswatter有良好的(IMO)的話,這可能複製多當列表大小不同,並在需要只使用迭代器會更好,因爲pop_front比實際需要的更多。我認爲以更多的代碼爲代價,下面的代碼「修復」迭代器。

template <typename ...T> 
std::list<std::tuple<T...>> simple_zip(std::list<T>... lst) 
{ 
    std::list<std::tuple<T...>> result; 
    struct { 
    void operator()(std::list<std::tuple<T...>> &t, int c, 
      typename std::list<T>::iterator ...it) { 
     if(c == 0) return; 
     t.emplace_back(std::move(*it++)...); 
     (*this)(t, c-1, it...); 
    } 
    } zip; 
    zip(result, std::min({lst.size()...}), lst.begin()...); 
    return result; 
} 

std::list<std::tuple<>> simple_zip() { 
    return {}; 
} 
+0

我假設'struct {int dummy; } pops [] = {(lst.pop_front(),0)...};'是強制參數解壓?總的來說,非常有意思的解+1 –

+0

+1哇,這是令人難以置信的優雅!我非常感動和感激。 一個小小的改變:我得到了'std :: min(lst.size()...)的編譯器錯誤; 'std :: min(1,2,3)'對我不起作用,但是'std :: min({1,2,3})'有,所以我加了大括號。 – user

+2

'struct {int dummy; } pops [] = {(lst.pop_front(),0)...};聰明的虐待,我必須記住這一點。 – ildjarn

4

這是約翰內斯第一個答案的漸進改進。它避免了虛擬struct並避免複製整個輸入列表(儘管這並不重要,除非一個列表比其他列表短)。我還對所有容器都進行了通用化。

但是,它需要一個樣板組,索引生成器,這是非常有用的反正

template< std::size_t n, typename ... acc > 
struct make_index_tuple { 
    typedef typename make_index_tuple< 
     n - 1, 
     std::integral_constant< std::size_t, n - 1 >, acc ... 
    >::type type; 
}; 

template< typename ... acc > 
struct make_index_tuple< 0, acc ... > 
    { typedef std::tuple< acc ... > type; }; 

「真正的」實現由一個簡單的功能,其需要從上述實用程序的輸出,和一個接口功能,其將包映射到元組。

template< typename ret_t, std::size_t ... indexes, typename lst_tuple > 
ret_t simple_zip(std::tuple< std::integral_constant< std::size_t, indexes > ... >, 
    lst_tuple const &lst) { 
    ret_t ret; 

    auto iters = std::make_tuple(std::get<indexes>(lst).begin() ...); 
    auto ends = std::make_tuple(std::get<indexes>(lst).end() ...); 

    while (std::max<bool>({ std::get<indexes>(iters) 
          == std::get<indexes>(ends) ... }) == false) { 
     ret.emplace_back(* std::get<indexes>(iters) ++ ...); 
    } 
    return ret; 
} 

template< typename ... T > 
std::list< std::tuple< typename T::value_type ... > > 
simple_zip(T const & ... lst) { 
    return simple_zip 
     < std::list< std::tuple< typename T::value_type ... > > > (
     typename make_index_tuple< sizeof ... lst >::type(), 
     std::tie(lst ...) 
    ); 
} 

至少,這使得Johannes看起來很容易。這是大多數可變模板算法的樣子,因爲如果沒有tuple,沒有辦法存儲類型 - 可變參數狀態,並且沒有辦法處理可變元組而無需一組索引或元遞歸函數。 (編輯:啊,現在約翰內斯使用尾遞歸本地函數定義局部禮包,做的一切,沒有tuple在所有真棒......如果你能處理所有的函數式編程;訴))

+2

好的代碼。 「std :: max < bool >({std :: get < indexes >(iters)== std :: get < indexes >(ends)...})== false」HAHA很聰明。 –

1

另一個版本:約翰內斯和Potatoswatter答案的組合,試圖儘量減少弄虛作假量

template <typename C, typename... Its> 
void simple_zip_details(C& c, size_t size, Its... its) 
{ 
    for (int i = 0; i < size; i++) 
     c.emplace_back(std::move(*its++)...); 
} 

template <typename... Ts> 
std::list<std::tuple<Ts...>> simple_zip(std::list<Ts>... lst) 
{ 
    std::list<std::tuple<Ts...>> result; 
    size_t size = std::min({ lst.size()... }); 
    simple_zip_details(result, size, lst.begin()...); 
    return result; 
} 
+0

有了我沒有測試過的免責聲明(我假設你做過),我對代碼的簡潔性印象非常深刻。 – user