mercredi 12 décembre 2018

Mix template and non-template visitor methods

Currently I am learning about the Visitor Pattern and try out various ideas. Below I have the code of my current setup, which I would like to get functioning somehow.

I would like to have two visitors, one that counts instances of Red and Blu separately and one that counts anything (one can assume, it's a Color)

This is of course solvable by simply implementing the second visitor analogously to the first one, however not using separate variables for counting, but just one. I think however this is unnecessary - if I had for example many, many different colours, the code would be very repetitive: All functions in that visitor would be same, they would simply increment one variable. Surely, there is an easier way, but how? According to the standard Visitor Pattern I have to implement for every color class a visit functions, thus this does not seem to be the right approach.

How would someone solve this problem?

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

Aucun commentaire:

Enregistrer un commentaire