Смешайте шаблоны и не шаблонные методы посетителя - PullRequest
0 голосов
/ 12 декабря 2018

В настоящее время я изучаю Шаблон посетителя и пробую различные идеи.Ниже у меня есть код моей текущей настройки, который я хотел бы получить как-нибудь.

Я хотел бы иметь двух посетителей, один, который подсчитывает экземпляры Red и Blu отдельно, а другой, который считаетчто угодно (можно предположить, что это Color)

Это, конечно, можно решить, просто внедрив второго посетителя аналогично первому, но не используя отдельные переменные для подсчета, а только одну.Однако я думаю, что в этом нет необходимости - если бы у меня было, например, много разных цветов, код был бы очень повторяющимся: все функции в этом посетителе были бы одинаковыми, они просто увеличивали бы одну переменную.Конечно, есть более простой способ, но как?Согласно стандартному шаблону посетителя, я должен реализовать для каждого цветового класса функции посещения, таким образом, это не совсем правильный подход.

Как бы кто-нибудь решил эту проблему?

#include <iostream>

class Color
{
public:
    virtual void accept(class Visitor*) = 0;
};

class Red: public Color
{
public:
    /*virtual*/
    void accept(Visitor*);
    void eye()
    {
        std::cout << "Red::eye\n";
    }
};
class Blu: public Color
{
public:
    /*virtual*/
    void accept(Visitor*);
    void sky()
    {
        std::cout << "Blu::sky\n";
    }
};

class Visitor
{
public:
    virtual void visit(Red*) = 0;
    virtual void visit(Blu*) = 0;
};

class CountVisitor: public Visitor
{
public:
    CountVisitor()
    {
        m_num_red = m_num_blu = 0;
    }
    /*virtual*/
    void visit(Red*)
    {
        ++m_num_red;
    }
    /*virtual*/void visit(Blu*)
    {
        ++m_num_blu;
    }
    void report_num()
    {
        std::cout << "Reds " << m_num_red << ", Blus " << m_num_blu << '\n';
    }
private:
    int m_num_red, m_num_blu;
};

class TemplateVisitor: public Visitor
{
public:
    TemplateVisitor() : num_of_colours(0) {}

    /*virtual*/
    template<class C>
    void visit(C* c)
    {
        ++num_of_colours;
    }
    void report_num()
    {
        std::cout << "Colours " << num_of_colours << '\n';
    }

private:
    int num_of_colours;

};


void Red::accept(Visitor *v)
{
    v->visit(this);
}

void Blu::accept(Visitor *v)
{
    v->visit(this);
}

int main()
{
    Color *set[] =
    {
        new Red, new Blu, new Blu, new Red, new Red, nullptr
    };
    CountVisitor count_operation;
    TemplateVisitor template_visitor;
    for (int i = 0; set[i]; i++)
    {
        set[i]->accept(&count_operation);
        set[i]->accept(&template_visitor);
    }
    count_operation.report_num();
    template_visitor.report_num();
}

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

Почему бы просто не использовать карту и добавить в цвет некоторую функцию для использования в качестве идентификатора?

class Color
{    
public:
    virtual void accept(class Visitor*) = 0;
    virtual std::string color_name() = 0; 

};

class Visitor
{
public:
    virtual void visit(Color* c);
};

class CountVisitor: public Visitor
{
    std::unordered_map<std::string, int> map; 

public:
    /*virtual*/
    void visit(Color* c)
    {
        map[c.color_name()]++;
    }
};
0 голосов
/ 13 декабря 2018

К сожалению, виртуальные методы и методы шаблона не могут совпадать.

Я имею в виду ... если ваш базовый класс Visitor требует

virtual void visit(Red*) = 0;
virtual void visit(Blu*) = 0;

реализация двух виртуальных методов впроизводные классы, вы не можете решить это обязательство одним методом шаблона

template<class C>
void visit(C* c)
{
    ++num_of_colours;
}

Вы должны написать два метода, абсолютно не шаблон, с точной подписью.Возможно, добавив также override, чтобы уменьшить риск ошибок.

  void visit (Red * r) override
   { ++num_of_colours; }

  void visit (Blu * b) override
   { ++num_of_colours; }

Очевидно, что вы можете определить шаблонный метод (возможно, с другим именем, но также visit(), если хотите), который вызывается обоимивиртуальные переопределенные методы

  template <typename C>
  void visit (C * c)
   { ++num_of_colours; }

  void visit (Red * r) override
   { visit<Red>(r); }

  void visit (Blu * b) override
   { visit<Blu>(b); }

Таким образом, вы можете реализовать логику посетителя в одном шаблонном методе и вызывать его всеми виртуальными методами

...