9

C++での単純な2コンテナのzip関数は次のとおりです。

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

これを可変個引数テンプレートを使用して任意の数のコンテナーに拡張するにはどうすればよいですか?

a of s(各リストに異なるタイプを含めることができます)general_zipを受け入れて、 aofsを返したいのですが。tuplelistlisttuple

4

3 に答える 3

14

これはうまくいくようです

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には、リストのサイズが異なる場合に必要以上にコピーされる可能性があり、pop_frontは実際に必要以上のことを行うため、イテレーターのみを使用する方がよいという良い(IMO)コメントがありました。次のコードは、より多くのコードを犠牲にしてイテレータを「修正」すると思います。

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 {};
}
于 2012-05-02T21:40:32.480 に答える
5

これは、ヨハネスの最初の答えを少しずつ改善したものです。ダミーstructを回避し、入力リスト全体をコピーすることを回避します(ただし、1つのリストが他のリストよりも短い場合を除いて、これはそれほど重要ではありません)。また、すべてのコンテナーで汎用的にしました。

しかし、それはボイラープレートパックインデックスジェネレータを必要とします、それはとにかく非常に便利です

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

少なくとも、これはヨハネスが簡単に見せたものを見通しに入れます。これは、ほとんどの可変個引数テンプレートアルゴリズムがどのように見えるかです。これは、。なしで型可変引数状態を格納する方法tupleがなく、インデックスのパックまたはメタ再帰関数なしで可変個引数タプルを処理する方法がないためです。(編集:ああ、今ヨハネスは末尾再帰ローカル関数を使用してローカルパックを定義し、それをまったく行わずtupleにすべてを実行しました。素晴らしい…すべての関数型プログラミングを処理できる場合; v)。)

于 2012-05-06T14:06:14.510 に答える
2

別のバージョン:ヨハネスとポテトスワッターの答えを組み合わせて、トリックの量を最小限に抑えようとしています(それでも私は楽しんでいました!)

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;
}
于 2013-09-29T14:00:45.213 に答える