Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement the "visitor pattern" with templates

I'm trying to implement a modified version of the visitor pattern in a parametric manner, avoiding in this way a "universal visitor" with a overload for each concrete element, but, due to I haven't a lot of experience in template programming I don't know how I can complete the "pattern".

Code:

// test.cpp
#include <iostream>
#include <vector>

using namespace std;

struct Base
{
    virtual ~Base() {}
    virtual void visit() = 0;
};

template<typename Visitor>
struct ElementBase : public Base
{
    // No virtual.
    void visit()
    {
        _e.visit(this);
    }

private:
    Visitor _e;
};

// Atoms.
template<typename Visitor>
struct ElementA : public ElementBase<Visitor>
{
    ElementA() : a(5) {}

    int a;
};

// Visitors.
struct VisitorA
{
    void visit(ElementBase<VisitorA> *a)
    {
        ElementA<VisitorA>* elto = dynamic_cast<ElementA<VisitorA>*>(a);

        cout << elto->a << endl;
    }

    /*
    void visit(ElementA<VisitorA> *a)
    {
        cout << a->a << endl;
    }
    */
};

std::vector<Base*> v;

int main()
{
    v.push_back(new ElementA<VisitorA>());

    for (auto i : v)
        i->visit();
}

This works fine and its output is 5 (as expected). But that I pretend is to make the same but directly with the second (commented) version of the "visit" in VisitorA.

Obviously, this doesn't work because "this" has the type ElementBase<...>*.

How can I downcast the pointer "this" to the actual derived class inside ElementBase?

like image 609
Peregring-lk Avatar asked Jul 10 '26 03:07

Peregring-lk


1 Answers

Like user786653 says, the Curiously Recurring Template Pattern can solve this

template<typename Visitor, typename Derived>
struct ElementBase : public Base
{
    void visit()
    {
        _e.visit(static_cast<Derived*>(this));
    }

private:
    Visitor _e;
};

// Atoms.
template<typename Visitor>
struct ElementA : public ElementBase<Visitor, ElementA<Visitor> >
{
    ElementA() : a(5) {}

    int a;
};

// Visitors.
struct VisitorA
{
    void visit(ElementA<VisitorA> *a)
    {
        cout << a->a << endl;
    }
};
like image 180
Peter Avatar answered Jul 11 '26 19:07

Peter



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!