如何使用BOOST_FOREACH同时迭代两个向量?

Can*_*hiu 33 c++ boost iterator boost-foreach

我想用BOOST FOREACH复制以下内容

std::vector<int>::const_iterator i1;
std::vector<int>::const_iterator i2;
for( i1 = v1.begin(), i2 = v2.begin();
     i1 < v1.end() && i2 < v2.end();
     ++i1, ++i2 )
{
     doSomething( *i1, *i2 );
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*sop 34

同时迭代两个东西称为"zip"(来自函数式编程),Boost有一个zip迭代器:

zip迭代器提供了同时并行迭代几个受控序列的能力.zip迭代器由迭代器元组构成.移动zip迭代器会并行移动所有迭代器.取消引用zip迭代器会返回一个元组,其中包含取消引用各个迭代器的结果.

请注意,它是一个迭代器,而不是一个范围,所以要使用BOOST_FOREACH它将不得不将其中两个填充到iterator_rangepair.所以它不会很漂亮,但有点小心你可能会想出一个简单的zip_range写:

BOOST_FOREACH(boost::tuple<int,int> &p, zip_range(v1, v2)) {
    doSomething(p.get<0>(), p.get<1>());
}
Run Code Online (Sandbox Code Playgroud)

或特殊情况2和使用std::pair而不是boost::tuple.

我想,既然doSomething可能有参数(int&, int&),实际上我们想要一个tuple<int&,int&>.希望它有效.

  • @Vlad:我也没有,但只要你知道它被称为"拉链",并且盲目相信任何你能想到的东西,Boost已经拥有,Google就是你的朋友:-) (3认同)
  • ..或者他可以只是'std:make_pair(beg,end)`因为BOOST_FOREACH也接受那些范围.(其中`beg`是`make_zip_iterator(make_tuple(v1.begin(),v2.begin())`等 (3认同)

pan*_*-34 16

如果你使用boost,我认为它应该像下面这样简单:

#include <boost/foreach.hpp>
#include <boost/range/combine.hpp>
std::vector<int> v1;
std::vector<int> v2;

// iterate over values
int i1, i2;
BOOST_FOREACH(boost::tie(i1, i2), boost::combine(v1, v2))
    std::cout << i1+i2 << "\n"; // sums two vectors

// iterate over references
typedef boost::tuple<int&, int&> int_ref_tuple;
BOOST_FOREACH(int_ref_tuple tup, boost::combine(v1, v2))
    tup.get<0>() = tup.get<1>(); // assigns one vector to another
Run Code Online (Sandbox Code Playgroud)

奇怪的是,boost :: combine没有记录.无论如何,对我有用.

  • 自1.56提升以来,它已被记录:http://www.boost.org/doc/libs/1_56_0/libs/range/doc/html/range/reference/utilities/combine.html (5认同)

Naw*_*waz 8

如果你想用同样的BOOST_FOREACH方式迭代两个向量,就像你在示例代码中所做的那样,那么你必须将两个向量封装在一个应该公开beginend函数的包装类中.这些函数返回自定义迭代器,用于迭代包装器,内部将迭代两个向量.听起来不太好,但这就是你要做的.

这是我第一次尝试实现这个(最小的实现只是为了演示基本的想法):

template<typename T>
struct wrapper
{
    struct iterator
    {
         typedef typename std::vector<T>::iterator It;
         It it1, it2;
         iterator(It it1, It it2) : it1(it1), it2(it2) {}
         iterator & operator++()
         {
            ++it1; ++it2; return *this;
         }
         iterator & operator *()
         {
            return *this;
         }
         bool operator == (const iterator &other)
         {
             return !(*this != other);
         }
         bool operator != (const iterator &other)
         {
             return it1 != other.it1 && it2 != other.it2;
         }
    };
    iterator begin_, end_;
    wrapper(std::vector<T> &v1,  std::vector<T> &v2) 
      : begin_(v1.begin(), v2.begin()),end_(v1.end(), v2.end())
    {
    }
    wrapper(const wrapper & other) : begin_(other.begin_), end_(other.end_) {}
    iterator begin() 
    {
          return begin_;
    }
    iterator end() 
    {
          return end_;
    }    
};
Run Code Online (Sandbox Code Playgroud)

以下是测试代码.因为它使用了通常的for循环,因为没有为C++ 0x安装了ideone,或者在包含它时我做错了.

int main() {
        std::vector<int> v1 = {1,2,3,4,5,6};
        std::vector<int> v2 = {11,12,13,14,15};
        wrapper<int> w(v1,v2);
        for(wrapper<int>::iterator it = w.begin(); it != w.end(); ++it)
        {
             std::cout << *it.it1 <<", "<< *it.it2 << std::endl;
        }
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

1, 11
2, 12
3, 13
4, 14
5, 15
Run Code Online (Sandbox Code Playgroud)

演示:http://ideone.com/Hf667

这仅适用于实验和学习目的,因为我并不认为它是完美的.可以有很多改进.@Steve已经发布了boost的解决方案.