Форвард объявить другую вложенную структуру в C ++ - PullRequest
0 голосов
/ 07 января 2019

Я пытаюсь реализовать шаблон посетителя внутри другого класса. MWE:

struct super
{
    struct base
    {
        virtual void accept(struct visitor& v);
        virtual ~base() {}
    };

    struct visitor
    {
        virtual void visit(base& b);
        virtual ~visitor() {}
    };

    struct special : public base
    {
        void accept(visitor& v) override { v.visit(*this); }
    };
};

int main() {}

Это жалуется, что special::accept на самом деле ничего не отменяет. Я думаю, это из-за того, что struct visitor отличается от visitor.

Замена позиции базы и посетителя (и перемещение объявления вперед в visitor::visit) устраняет эту ошибку (но затем говорит, что аргумент в v.visit(*this) не будет совпадать).

Можно ли реализовать шаблон посетителя внутри другого класса? Почему моя предварительная декларация не работает?

Ответы [ 2 ]

0 голосов
/ 08 января 2019

Объявление

struct super
{
    struct base
    {
        virtual void accept(struct visitor& v);
        virtual ~base() {}
    };
};

Не делает visitor членом base и не членом super. Это на самом деле вперед объявляет глобальный ::visitor. Вот почему в C ++ считается очень плохим стилем - объявлять тип вперед в каком-то другом объявлении. Функция базового класса accept имеет подпись void accept(::visitor&), но производный класс имеет подпись void accept(super::visitor&). MWE, который вы написали, будет эквивалентен следующему коду:

struct super
{
    struct base
    {
        // Declares ::visitor
        // Same signature as: virtual void accept(::visitor&);
        virtual void accept(struct visitor& v);
        virtual ~base() {}
    };

    // Declares super::base::visitor
    struct visitor
    {
        virtual void visit(base& b);
        virtual ~visitor() {}
    };

    struct special : public base
    {
        // Must have signature void accept(::visitor&) to override
        void accept(::visitor& v) override;
    };
};

struct visitor
{
    virtual void visit(super::base& b);
    virtual ~visitor() {}
};

inline void super::special::accept(::visitor& v) { v.visit(*this); }

int main() {}
0 голосов
/ 07 января 2019

Когда вы делаете

virtual void accept(struct visitor& v);

Вы ожидаете объявить visitor в наименьшее пространство имен или область блока, содержащая объявление . Это означает, что visitor is scoped to the global namespace in this case. Specials`'s

void accept(visitor& v)

с другой стороны захватывает super::visitor. Поскольку это разные типы, компилятор верен.

Что вам нужно сделать, это переместить предварительное объявление visitor в область действия super, например

struct super
{
    struct visitor;
    struct base
    {
        virtual void accept(visitor& v);
        virtual ~base() {}
    };

    struct visitor
    {
        virtual void visit(base& b);
        virtual ~visitor() {}
    };

    struct special : public base
    {
        void accept(visitor& v) override { v.visit(*this); }
    };
};

int main() {}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...