We can imagine even weaker concepts than ForwardIterator! For example, one useful thing you can do with a ForwardIterator is to make a copy of it, save the copy, and use it to iterate twice over the same data. Manipulating the iterator (or copies of it) doesn't affect the underlying range of data at all. But we could invent an iterator like the one in the following snippet, where there is no underlying data at all, and it's not even meaningful to make a copy of the iterator:
class getc_iterator {
char ch;
public:
getc_iterator() : ch(getc(stdin)) {}
char operator*() const { return ch; }
auto& operator++() { ch = getc(stdin); return *this; }
auto operator++(int) { auto result(*this); ++*this; return result; }
bool operator==(const getc_iterator&) const { return false; }
bool operator!=(const...