당신은 데카르트의 제품을 생성하기 위해 가변 인자 템플릿을 사용할 수 있습니다 작성할 수 있습니다. 아래의 코드는 @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
이 필요하지는 않습니다).
위의 내용을 재사용 가능한 기능에 넣을 수없는 이유는 무엇입니까? – stijn
그다지 어렵지 않아야합니다. 시작 튜플과 종료 튜플을 저장하고, 실행중인 튜플을 사전 순으로 증가시키는 실제 반복자로 사용하십시오. –
@stijn - 3 개 또는 4 개의 중첩 루프가있을 수 있습니다. – Loom