Code Link:
I'd like to create a wrapper around a generator to be used in a for-loop:
#include <functional>
#include <iostream>
#include <optional>
// some move-only generator, e.g. it could read some read-once input stream
class Generator {
public:
Generator() {}
Generator(const Generator&) = delete;
Generator(Generator&&) = default;
bool hasMore() { return _value < 5; }
void next() { _value++; }
int value() const { return _value; }
private:
int _value = 0;
};
// wrapper around Generator to make it usable in a for loop
class Iterable {
public:
Iterable(Generator gen) : _gen(std::move(gen)) {}
class EndIterator {};
class Iterator {
public:
Iterator(const Iterator& other) = delete;
Iterator(Generator gen) : _gen(std::move(gen)) {}
bool operator!=(EndIterator other) { return _gen.hasMore(); }
Iterator& operator++() {
_gen.next();
return *this;
}
int operator*() const { return _gen.value(); }
private:
bool _done = false;
int _next;
Generator _gen;
};
Iterator begin() && { return Iterator(std::move(_gen)); }
EndIterator end() { return {}; }
private:
Generator _gen;
};
int main() {
Iterable iterable{Generator{}};
for (auto i : iterable) {
std::cout << i << std::endl;
}
return 0;
}
I made Iterator::begin()
to operator on an rvalue this
because it moves the generator into the Iterator
. However, I get the following error message:
<source>: In function 'int main()':
<source>:55:19: error: passing 'Iterable' as 'this' argument discards qualifiers [-fpermissive]
55 | for (auto i : iterable) {
| ^~~~~~~~
<source>:45:14: note: in call to 'Iterable::Iterator Iterable::begin() &&'
45 | Iterator begin() && { return Iterator(std::move(_gen)); }
| ^~~~~
Compiler returned: 1
Removing &&
from Iterator::begin
works, but feels semantically wrong. Is there a better option to achieve what I am trying to do and still use it in a for loop?