2013-05-22 2 views
1

내가 BOOST이 STL과 같은 컨테이너 (직교 제품)

내가 Boost.Foreach 단일 구조에서 2 개 루프 (캡슐화 의미
typedef std::vector<int>::const_iterator Iterator; 

for(Iterator i = v1.begin(), ie = v1.end(); i != ie; ++i) { 
    for(Iterator j = v2.begin(), je = v2.end(); j != je; ++j) { 
    doSomething(*i, *j); 
    } 
} 

, 부스트와 다음 감소하고 싶습니다 반복하는 방법 .Range, Boost.Iterator 등). 내가보고 싶어하는 다음과 같은 좋아하는 것 (그것은 단지 생각이다. 나는보고 싶은 것을 정확하게 쓰지 않는다)

BOOST_FOREACH(boost::tuple<int,int> &p, ..._range(v1, v2)) { 
    doSomething(p.get<0>(), p.get<1>()); 
} 

어떻게 할 수 있는가?

편집 : 그런데는, 파이썬에서 방금

for (x1,x2,x3) in (l1,l2,l3): 
print "do something with", x1, x2, x3 
+1

위의 내용을 재사용 가능한 기능에 넣을 수없는 이유는 무엇입니까? – stijn

+1

그다지 어렵지 않아야합니다. 시작 튜플과 종료 튜플을 저장하고, 실행중인 튜플을 사전 순으로 증가시키는 실제 반복자로 사용하십시오. –

+0

@stijn - 3 개 또는 4 개의 중첩 루프가있을 수 있습니다. – Loom

답변

3

당신은 데카르트의 제품을 생성하기 위해 가변 인자 템플릿을 사용할 수 있습니다 작성할 수 있습니다. 아래의 코드는 @zch의 excellent answer에 대한 다른 질문입니다.

#include <tuple>      // make_tuple, tuple 
#include <utility>      // pair 
#include <vector>      // vector 

namespace detail { 

// the lambda is fully bound with one element from each of the ranges 
template<class Op> 
void insert_tuples(Op op) 
{ 
     // evaluating the lambda will insert the currently bound tuple 
     op(); 
} 

// "peal off" the first range from the remaining tuple of ranges 
template<class Op, class InputIterator1, class... InputIterator2> 
void insert_tuples(Op op, std::pair<InputIterator1, InputIterator1> head, std::pair<InputIterator2, InputIterator2>... tail) 
{ 
     // "peal off" the elements from the first of the remaining ranges 
     // NOTE: the recursion will effectively generate the multiple nested for-loops 
     for (auto it = head.first; it != head.second; ++it) { 
       // bind the first free variable in the lambda, and 
       // keep one free variable for each of the remaining ranges 
       detail::insert_tuples(
         [=](InputIterator2... elems) mutable { op(it, elems...); }, 
         tail... 
       ); 
     } 
} 

}  // namespace detail 

// convert a tuple of ranges to the range of tuples representing the Cartesian product 
template<class OutputIterator, class... InputIterator> 
void cartesian_product(OutputIterator result, std::pair<InputIterator, InputIterator>... dimensions) 
{ 
     detail::insert_tuples(
       [=](InputIterator... elems) mutable { *result++ = std::make_tuple(*elems...); }, 
       dimensions... 
     ); 
} 

이처럼 호출 할 수

int main() 
{ 
    bool b[] = { false, true }; 
    int i[] = { 0, 1 }; 
    std::string s[] = { "Hello", "World" }; 

    std::vector< std::tuple<bool, int, std::string> > cp = { 
      std::make_tuple(false, 0, "Hello") , 
      std::make_tuple(false, 0, "World"), 
      std::make_tuple(false, 1, "Hello"), 
      std::make_tuple(false, 1, "World"), 
      std::make_tuple(true, 0, "Hello"), 
      std::make_tuple(true, 0, "World"), 
      std::make_tuple(true, 1, "Hello"), 
      std::make_tuple(true, 1, "World") 
    }; 

    std::vector< std::tuple<bool, int, std::string> > result; 
    cartesian_product(
      std::back_inserter(result), 
      std::make_pair(std::begin(b), std::end(b)), 
      std::make_pair(std::begin(i), std::end(i)), 
      std::make_pair(std::begin(s), std::end(s)) 
    ); 

    std::cout << std::boolalpha << (result==cp) << "\n"; 

    // now use a single flat loop over result to do your own thing 
    for (auto t: result) { 
     std::cout << std::get<0>(t) << ", "; 
     std::cout << std::get<1>(t) << ", "; 
     std::cout << std::get<2>(t) << "\n"; 
    } 
} 

온라인 output.

나는 Boost.Range에 익숙하지 않지만, Boost 범위를 사용하도록 반복기 쌍을 쉽게 적용 할 수 있습니다. 한 가지 단점은 증분이되지 않는다는 것입니다. 앞으로 전체 카티 전 곱을 생성해야만 반복 할 수 있습니다 (질문의 코드에 break이 필요하지는 않습니다).

+0

'detail :: insert_tuples' (아마도 더 나은 이름으로)을 사용하여 벡터를 만들지 않고 교차 제품을 직접 반복 할 수 있습니다. 루프의 몸체를 람다 (lambda)로 제공하십시오. – zch

+0

@zch 예 좋은 점은 iterator (연산자 ++, operator * 및 end() iterator 사용)보다 원거리 for 루프와 비슷하지만. 예. 실행 시간 조건에 따라 루프를 중단 하시겠습니까? – TemplateRex

+0

예, 질문은 for 루프에 관한 것입니다. 예외를 사용하거나 람다가'false'를 반환 할 때 코드를 변경하는 것과 같이 중단을 일으키는 방법이 있지만 완벽하지는 않다는 것에 동의합니다. – zch