Вложенный класс «не называет тип» - PullRequest
2 голосов
/ 27 мая 2020

Я получаю следующую ошибку:

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

С этим кодом:

#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;
        }


    };
};

Оказывается, перемещение begin функции под вложенный класс Iterator делает эту компиляцию.

Но это странно - разве вложенные классы не следуют тем же правилам доступа, что и любой другой член, что означает отсутствие необходимости в прямых ссылках?

I поискал другие вопросы на сайте, касающиеся именно этой проблемы, похоже, не нашел ответа.

1 Ответ

2 голосов
/ 27 мая 2020

Из комментария к вопросу

Также - у меня нет проблем с вызовом функции-члена f в функции-члене q, где f определяется после q. Можете ли вы объяснить, почему последний пример отличается от ситуации, описанной в этом вопросе?

Согласно стандарту C ++ 20 (члены класса 11.4)

6 Полное- контекст класса класса:

> (6.1) - тело функции (9.5.1),

(6.2) - аргумент по умолчанию (9.3.3.6),

(6.3) - спецификатор noexcept (14.5) или

(6.4) - инициализатор члена по умолчанию

в пределах спецификации члена класса

Итак, внутри всего контекста класса имя функции f видно в теле функции q.

Однако внутренний класс объявлен вне полного контекста класса. Таким образом, в соответствии со стандартом C ++ 20 (6.5.1 поиск неквалифицированного имени)

7 Имя, используемое в определении класса X23 вне контекста полного класса (11.4) X, должно быть объявлено одним из следующих способов:

> (7.1) - до его использования в классе X или быть членом базового класса X (11.8), или ...

Таким образом, имя внутреннего класса Iterator должно быть объявлено до его использования в качестве возвращаемого типа функции-члена.

Вместо имени Iterator вы можете использовать, например, место держатель auto в качестве типа возврата.

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