Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

need a virtual template member workaround

Tags:

I need to write a program implementing the visitor design pattern. The problem is that the base visitor class is a template class. This means that BaseVisited::accept() takes a template class as a parameter and since it uses 'this' and i need 'this' to point to the correct runtime instance of the object, it also needs to be virtual.
I'd like to know if there's any way around this problem.

template <typename T>
class BaseVisitor {
  public:
    BaseVisitor();
    T visit(BaseVisited *visited);
    virtual ~BaseVisitor();
}


class BaseVisited {
  BaseVisited();
  template <typename T>
    virtual void accept(BaseVisitor<T> *visitor) { visitor->visit(this); }; // problem
  virtual ~BaseVisited();
}
like image 650
yurib Avatar asked May 30 '10 18:05

yurib


People also ask

Can template member function be virtual?

No, template member functions cannot be virtual.

Can a non templated class have a templated member function?

A non-template class can have template member functions, if required. Notice the syntax. Unlike a member function for a template class, a template member function is just like a free template function but scoped to its containing class.

What functions Cannot be virtual?

A virtual function cannot be global or static because, by definition, a virtual function is a member function of a base class and relies on a specific object to determine which implementation of the function is called. You can declare a virtual function to be a friend of another class.

What is virtual void in C++?

A C++ virtual function is a member function in the base class that you redefine in a derived class. It is declared using the virtual keyword. It is used to tell the compiler to perform dynamic linkage or late binding on the function.


2 Answers

What you should do is separate the BaseVisitor.

class BaseVisited;
class BaseVisitorInternal {
public:
    virtual void visit(BaseVisited*) = 0;
    virtual ~BaseVisitorInternal() {}
};
class BaseVisited {
    BaseVisited();
    virtual void accept(BaseVisitorInternal* visitor) { visitor->visit(this); }
};
template<typename T> class BaseVisitor : public BaseVisitorInternal {
    void visit(BaseVisited* visited);
};

If you need BaseVisited's derived classes to be templated too AND pass their correct types/overloads to visit, you're officially dead.

like image 191
Puppy Avatar answered Sep 29 '22 16:09

Puppy


I came up with something slightly different than DeadMG:

class BaseVisited;

class IVisitor {
  public:
    virtual void visit(BaseVisited *visited) = 0;
    virtual ~IVisitor();
};

template <typename T>
class BaseVisitor : public IVisitor {
  public:
    BaseVisitor();
    virtual void visit(BaseVisited *visited);
    virtual ~BaseVisitor();
    virtual T result();
};


class BaseVisited {
  public:
    BaseVisited();
    virtual void accept(IVisitor *visitor) { visitor->visit(this); };
    virtual ~BaseVisited();
};

Mine has an extra result() member function that lets you retrieve the result of the last visit.

like image 24
Emile Cormier Avatar answered Sep 29 '22 16:09

Emile Cormier