Many posts about const iterators (example), but none in the context of loops like:
for (const auto it: container) { ... }
When I started implementing, I was encouraged by the compiler's complaints about missing begin
and end
, hoping such complaints can guide me to fill in the missing pieces. I was wrong. The following code compiles fine though it surely lacks the equivalent of both operator
and operator!=
:
#include <iostream>
template<class T> class List { public:
const T *head;
const List<T> *tail;
List(const T *h, const List<T> *t):head(h),tail(t){}
const T *operator*() const { return head; } };
template<class T> const List<T> *begin(const List<T> *l) { return l; }
template<class T> const List<T> *end (const List<T> *l) { return nullptr; }
class Person { public: int age; Person(int a):age(a){} };
typedef List<Person> Persons;
int main(int argc, char **argv) {
Person *p1 = new Person(16);
Person *p2 = new Person(27);
Person *p3 = new Person(38);
Persons *persons = new Persons(p1,
new Persons(p2,
new Persons(p3, nullptr)));
for (const auto p: persons) { std::cout << (*p)->age << "\n"; }
return 0; }
How come this code compiles?
CodePudding user response:
You have not defined
and !=
, but they are perfectly well-defined for your iterator type, const List<T>*
, because is a pointer type. However, the default behavior of
does not do what you want, which would be to follow the tail
pointer.
To imbue your iterator with special knowledge of how
should be implemented, you would want to use a separate, custom iterator class, rather than using a pointer.
I also made some other changes to your code:
- The
List
type is made iterable, notList*
. That means thebegin
andend
functions are not defined on pointers, but on the List object itself, and we iterate over*persons
rather thanpersons
. - In
for (const auto p : *persons)
,p
is aPerson
, not a pointer.
#include <iostream>
template<class T> class List { public:
const T *head;
const List<T> *tail;
List(const T *h, const List<T> *t):head(h),tail(t){}
const T *operator*() const { return head; }
class const_iterator {
const List<T>* cur = nullptr;
public:
explicit const_iterator(const List<T>* list) : cur(list) {}
const_iterator& operator () {
cur = cur->tail;
return *this;
}
bool operator!=(const const_iterator& other) const {
return cur != other.cur;
}
const T& operator*() const {
return *cur->head;
}
};
const_iterator begin() const {
return const_iterator(this);
}
const_iterator end() const {
return const_iterator(nullptr);
}
};
class Person { public: int age; Person(int a):age(a){} };
typedef List<Person> Persons;
int main(int argc, char **argv) {
Person *p1 = new Person(16);
Person *p2 = new Person(27);
Person *p3 = new Person(38);
Persons *persons = new Persons(p1,
new Persons(p2,
new Persons(p3, nullptr)));
for (const auto p: *persons) {
std::cout << p.age << "\n";
}
return 0;
}