Cartesian product using Variadic iterators and patterns

I am trying to create a function to create a Cartesian product of a variable number of input ranges using the STL style. My main format is that the function takes a fixed range and the beginning of the output range, and then the variational number of bidirectional input iterators.

template <
    typename BidirectionalIterator,
    typename OutputIterator,
    typename... Args
>
void cartesian_product(
    BidirectionalIterator first,
    BidirectionalIterator last,
    OutputIterator result,
    Args&&... args
);

My idea for argsis what I am doing from it tuple, then I iterate over this one tupleto extract the elements. This would require me to follow a few basic steps:

  • Make tupleoutargs
  • Separate each iterator in the newly created tuple
  • Build each iterator in sequence tuplein sequence so that we get all possible combinations of values โ€‹โ€‹in ranges.

3: A = {0, 1} B = {2, 3}, A x B = {(0, 2), (0, 3), (1, 2), (1, 3)}.

, :

auto arg_tuple = std::make_tuple(std::forward<Args>(args)...);

. , - push_back , *result . , ostream , , :

template <typename Tuple, typename T>
auto operator<<(const Tuple &lhs, const T &rhs)
    -> decltype(std::tuple_cat(lhs, std::make_tuple(rhs)))
{
    return std::tuple_cat(lhs, std::make_tuple(rhs));
}

, , . - :

template <typename T>
auto pre_increment(T &x) -> decltype(++x) {
    return ++x;
}

3000 for_each tuple, .

, ++ 14 . ++ 11.

boost::fusion , , .

+4
2

:

#include <iostream>
#include <tuple>
#include <vector>

template <typename T, typename B>
bool increment(const B& begins, std::pair<T,T>& r) {
  ++r.first;
  if (r.first == r.second) return true;
  return false;
}
template <typename T, typename... TT, typename B>
bool increment(const B& begins, std::pair<T,T>& r, std::pair<TT,TT>&... rr) {
  ++r.first;
  if (r.first == r.second) {
    r.first = std::get<std::tuple_size<B>::value-sizeof...(rr)-1>(begins);
    return increment(begins,rr...);
  }
  return false;
}

template <typename OutputIterator, typename... Iter>
void cartesian_product(
  OutputIterator out,
  std::pair<Iter,Iter>... ranges
) {
  const auto begins = std::make_tuple(ranges.first...);
  for (;;) {
    out = { *ranges.first... };
    if (increment(begins, ranges...)) break;
  }
}

struct foo {
  int i;
  char c;
  float f;
};

int main(int argc, char* argv[]) {

  std::vector<int> ints { 1, 2, 3 };
  std::vector<char> chars { 'a', 'b', 'c' };
  std::vector<float> floats { 1.1, 2.2, 3.3 };

  std::vector<foo> product;

  cartesian_product(
    std::back_inserter(product),
    std::make_pair(ints.begin(), ints.end()),
    std::make_pair(chars.begin(), chars.end()),
    std::make_pair(floats.begin(), floats.end())
  );

  for (const auto& x : product)
    std::cout << x.i << ' ' << x.c << ' ' << x.f << std::endl;

}

cartesian_product , , .

, , , begin, end, .

+2

++ 17 std::apply(). ++ 14 . fmap a tuple :

template <class Tuple, class F>
auto fmap(Tuple&& tuple, F f) {
    return apply([=](auto&&... args){
        return std::forward_as_tuple(f(std::forward<decltype(args)>(args))...);
    }, std::forward<Tuple>(tuple));
}

:

auto deref_all = fmap(iterators, [](auto it) -> decltype(auto) { return *it; });
auto incr_all = fmap(iterators, [](auto it) { return ++it; });
+4

Source: https://habr.com/ru/post/1678008/


All Articles