The following code fails to compile if you uncomment the commented line. (Compiler Explorer)
Why is that?
I imagine the reason is that the iota_view
of Foo
s doesn't know how to advance a Foo
. But how do I make it know?
#include <iostream>
#include <ranges>
struct Foo {
int x;
Foo() : x{-1} {}
Foo(int x) : x{x} {}
using difference_type = int;
friend auto operator<=>(Foo const& a, Foo const& b) {
return a.x <=> b.x;
}
friend bool operator==(Foo const& a, Foo const& b) {
return a.x == b.x;
}
auto& operator++() {
++x;
return *this;
}
auto operator++(int) {
auto r = *this;
++x;
return r;
}
};
int main () {
auto ints = std::views::iota(1, 30);
for (auto i : ints) {}
std::cout << ints[15] << std::endl;
auto foos = std::views::iota(Foo{1}, Foo{30});
for (auto i : foos) {}
//std::cout << foos[15] << std::endl;
}
The example usees std-ranges, but I'm interested in an answer for range-v3 too, should they differ.
Take a look at this page: https://en.cppreference.com/w/cpp/ranges/iota_view/iterator
To be a random access range, the type needs to be "advanceable". This requires operator+
, operator+=
, operator-
and operator-=
(and operator--
to be a bidirectional range).
Advancing an iterator by n
will just add n
to the current value with operator+=
or operator+
.
Example implementations:
struct Foo {
// ...
Foo& operator--() { --x; return *this; }
Foo operator--(int) { auto r = *this; --*this; return r; }
friend Foo operator+(Foo l, int r) { return Foo{ l.x + r }; }
friend Foo operator+(int l, Foo r) { return Foo{ l + r.x }; }
friend Foo operator-(Foo l, int r) { return Foo{ l.x - r }; }
friend int operator-(Foo l, Foo r) { return l.x - r.x; }
Foo& operator+=(int r) { return *this = *this + r; }
Foo& operator-=(int r) { return *this = *this - r; }
};