Reputation: 11317
Is it possible to use the boost::iterators library to create iterators that show the combined results of 2 ranges? Note that for usage, we need the output to be iterators. Nor do we expect to first manually create a vector of all combinations. (Note: We compile with C++17)
A contrived example:
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;
I've checked the documentation of boost::iterators and found:
Am I correct to conclude that in this situation the only option is to write customer iterator by hand?
Upvotes: 4
Views: 327
Reputation: 63152
Am I correct to conclude that in this situation the only option is to write customer iterator by hand?
Pretty much yes. You might want to decompose it into an iterator adaptor that repeats each element N times, and one that repeats the whole range M times, which would allow you to zip
the pair of those.
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;
}
};
Upvotes: 1