문제

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.

도움이 되었습니까?

해결책

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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top