3

I'm getting the following error:

main.cpp:18:5: error: 'Iterator' does not name a type
   18 |     Iterator begin() {
      |     ^~~~~~~~

With this code:

#include <iostream>
#include <iostream>
#include <memory>
#include <fstream>
#include <filesystem>

using namespace std;

class Numbers {
    private:
    int current;
    int end;

    public:

    Numbers(int end) : current(0), end(end) {}

    Iterator begin() {
        return Iterator(this);
    }

    bool operator==(const Numbers& other) const {
        return current == other.current && end == other.end;
    }

    bool operator!=(const Numbers& other) const {
        return !(other == *this);
    }

    class Iterator {
        private:
        Numbers* range;

        public:
        using value_type = int;
        using difference_type = ptrdiff_t;
        using pointer = int*;
        using reference = int&;
        using iterator_category = input_iterator_tag;

        Iterator(Numbers* range) : range(range) {}

        int operator*() const {
            return range->current;
        }

        int* operator->() const {
            return &range->current;
        }

        bool operator==(const Iterator& other) const {
            return other.range == range;
        }

        bool operator!=(const Iterator& other) const {
            return !(*this == other);
        }

        Iterator& operator++() {
            range->current++;
            return *this;
        }


    };
};

It turns out that moving the begin function under the nested Iterator class makes this compile.

But it's odd - don't nested classes follow the same access rules as any other member, meaning no need for forward-references?

I searched the other questions on the site regarding this exact issue, didn't seem to find an answer.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Aviv Cohn
  • 15,543
  • 25
  • 68
  • 131
  • And what does Iterator mean?! The inner class should be declared before using its name. – Vlad from Moscow May 26 '20 at 21:34
  • @VladfromMoscow I see. I of course thought it was the case, but then, as I noted here, I read on SO that it might not be the case. Also - I have no problem calling member function `f` in member function `q` where `f` is defined after `q`. Can you explain why the latter example is different than the situation described in this question? Thank you – Aviv Cohn May 26 '20 at 21:37

1 Answers1

2

From a comment to the question

Also - I have no problem calling member function f in member function q where f is defined after q. Can you explain why the latter example is different than the situation described in this question?

According to the C++ 20 Standard (11.4 Class members)

6 A complete-class context of a class is a

> (6.1) — function body (9.5.1),

(6.2) — default argument (9.3.3.6),

(6.3) — noexcept-specifier (14.5), or

(6.4) — default member initializer

within the member-specification of the class

So inside the complete class context the name of the function f is visible within the body of the function q.

However the inner class is declared outside the complete class context. So according to the C++ 20 Standard (6.5.1 Unqualified name lookup)

7 A name used in the definition of a class X23 outside of a complete-class context (11.4) of X shall be declared in one of the following ways:

> (7.1) — before its use in class X or be a member of a base class of X (11.8), or ...

So the name of the inner class Iterator must be declared before its using as a return type of a member function.

Instead of the name Iterator you could use for example the place holder auto as the return type.

auto begin() {
    return Iterator(this);
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 2
    TL;DR: the definitions of member functions are implicitly "placed after" the class, so they can see everything in the class even if some things were declared after where you wrote the body of the function. There is no "forward declarations are unnecessary for class members" rule in the language. The declarations of members remain in the class in the order you wrote them, so the signature of `begin` can't see `Iterator`. – HTNW May 26 '20 at 21:51