首页 > 解决方案 > 2个范围的所有组合的迭代器

问题描述

是否可以使用 boost::iterators 库来创建显示 2 个范围的组合结果的迭代器?请注意,为了使用,我们需要输出是迭代器。我们也不希望首先手动创建所有组合的向量。(注:我们用 C++17 编译)

一个人为的例子:

auto v = std::vector<int>({1,2,3});
auto s = std::set<double>({0.5, 1.5});
auto range = combineElements(v.begin(), v.end(), s.begin(), s.end(), [](int i, double d){ return std::pair{i, d}; });
for (auto [i, d] : range)
   std::cout << std::to_string(i) << ',' <<std::to_string(d) << ";";
// Expected output: 1,0.5;1,1.5;2,0.5;2,1.5;3,0.5;3,1.5;

我检查了boost::iterators的文档,发现:

我是否正确得出结论,在这种情况下,唯一的选择是手动编写客户迭代器?

标签: c++boostc++17cartesian-productboost-iterators

解决方案


我是否正确得出结论,在这种情况下,唯一的选择是手动编写客户迭代器?

几乎是的。您可能希望将其分解为一个迭代器适配器,该适配器将每个元素重复 N 次,另一个将整个范围重复 M 次,这将允许您使用zip这对。

template <class Iterator>
class repeat_iterator
  : public boost::iterator::iterator_adaptor< repeat_iterator<Iterator>, Iterator > 
{
  typedef boost::iterator::iterator_adaptor< repeat_iterator<Iterator>, Iterator > super_t;
  friend class boost::iterator::iterator_core_access;
  size_t len = 1;
  size_t curr = 0;

public:
  repeat_iterator() {}

  explicit repeat_iterator(Iterator x, size_t len, curr = 0)
      : super_t(x), len(len), curr(curr) {}

private:
  void increment() { 
      if (++curr == len) { 
          curr = 0;
          ++base_reference(); 
      }
  }
  void decrement() {
      if (curr-- == 0) {
          curr = len - 1;
          --base_reference(); 
      } 
  }
  void advance(typename super_t::difference_type n)
  {
      n += curr;
      base_reference() += n / len;
      curr = n % len;
  }
  template <class OtherIterator>
  typename super_t::difference_type
  distance_to(unstride_iterator<OtherIterator> const& y) const
  {
      return ((base() - y.base()) * len) + (curr - y.curr);
  }
};

template <class Iterator>
class cycle_iterator
  : public boost::iterator::iterator_adaptor< cycle_iterator<Iterator>, Iterator > 
{
  typedef boost::iterator::iterator_adaptor< cycle_iterator<Iterator>, Iterator > super_t;
  friend class boost::iterator::iterator_core_access;
  Iterator first;
  Iterator last;

public:
  cycle_iterator() {}

  explicit cycle_iterator(Iterator first, Iterator last)
      : super_t(first), first(first), last(last) {}

private:
  void increment() { 
      if (++base_reference() == last) { 
          base_reference() = first; 
      }
  }
  void decrement() {
      if (base_reference() == first) {
          base_reference() = last - 1; 
      } 
  }
  void advance(typename super_t::difference_type n)
  {
      n += std::distance(first, base_reference());
      n %= std::distance(first, last);
      base_reference() = first + n;
  }
};

推荐阅读