Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the Visitor Pattern the fastest way to differentiate parameter types in C++?

Is the Visitor Pattern the fastest way to accomplish method parameter type identification (effectively single dispatch on a parameter, not a member's class) in C++? I might know the exact method(s) I want to invoke on elements of not-yet-know subtype, so invariably making an additional virtual method call like V::visit(A *) in A::accept(V &v) { v.visit(this); } is undesirable.

// Is the Visitor pattern recommended here?  (E inherits D inherits B.)
class Foo {
public:
  virtual void visit(B *) { result = 3; }
  virtual void visit(D *) { result = 4; }
  virtual void visit(E *) { result = 5; }
private:
  int result;
}; // class Foo

// Need to add generic interface to B and its children ...
class B {
public:
  virtual void accept(class Foo &f) { f.visit(this); }
}; // class B

I'd like something functionally equivalent the following but with O(1) cost, which is AFAIK not possible with dynamic_cast<> or typeid() ladders, since std::type_info can't be a constexpr/switchable.

// O(n) search cost might get nasty with bigger hierarchies.
int foo(B *b) {
  if (typeid(b) == typeid(B *)) { return 1; }
  if (typeid(b) == typeid(D *)) { return 2; }
  if (typeid(b) == typeid(E *)) { return 3; }
  return -1;
}

What are my options here? Thanks for the advice!

Edit: Changed sample code to feed results through field, such that multiple signatures aren't needed for different method types. Thanks, Maurice!

Final decision: In addition to not liking the mandatory double dispatch cost of the Visitor Pattern, I also wanted to avoid the interface bloat of overloading foo(), but I don't think that there is a known clean pattern to do this. I ended up just doing straight static overloads and called it a day. Anyway, my wanting to encapsulate overloading inside a function is probably a questionable goal at best. Thanks, Maurice for the response.

like image 392
Jeff Avatar asked Aug 31 '10 17:08

Jeff


People also ask

What is visitor pattern good for?

The visitor pattern is useful when you want to process a data structure containing different kinds of objects, and you want to perform a specific operation on each of them, depending on its type. Your example is not the best, since you pass a single homogeneous list as input, so there is really no need for the pattern.

When should we use visitor design pattern?

Visitor design pattern is one of the behavioral design patterns. It is used when we have to perform an operation on a group of similar kind of Objects. With the help of visitor pattern, we can move the operational logic from the objects to another class.

What is visitor pattern C++?

Visitor in C++ Visitor is a behavioral design pattern that allows adding new behaviors to existing class hierarchy without altering any existing code. Read why Visitors can't be simply replaced with method overloading in our article Visitor and Double Dispatch.


1 Answers

In fact, the interfaces need not be duplicated. The subclasses of the visitor can handle the details of the operation. In your case:

class Visitor {
    virtual void visit(B*) = 0;
    virtual void visit(D*) = 0;
    virtual void visit(E*) = 0;
}

class Foo: public Visitor {
private:
    int result;
public:
    void visit(B*) { result = 3; }
    void visit(D*) { result = 4; }
    void visit(E*) { result = 5; }
    int apply(A* a) {
        a->accept(this);
        return result;
    }
}

So, only one accept() method is needed in each class.

All the alternatives to the visitor pattern I can think of involve some kind of run-time searching, so yes, IMHO, the visitor pattern is the fastest way.

like image 186
Maurice Perry Avatar answered Sep 23 '22 10:09

Maurice Perry