Является ли шаблон посетителя самым быстрым способом дифференциации типов параметров в C ++? - PullRequest
8 голосов
/ 31 августа 2010

Является ли шаблон посетителя самым быстрым способом определения типа параметра метода (фактически одной отправки по параметру, а не по классу члена) в C ++?Я мог бы знать точные методы, которые я хочу вызывать для элементов еще не известного подтипа, поэтому создание дополнительного вызова виртуального метода, такого как V::visit(A *) в A::accept(V &v) { v.visit(this); }, нежелательно.

// 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

Мне бы хотелось что-то функционально эквивалентное следующему, но с затратами O (1), что AFAIK невозможно с лестницами dynamic_cast <> или typeid (), поскольку std::type_info не может быть 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;
}

Какие у меня есть варианты?Спасибо за совет!

Редактировать: Изменен пример кода для подачи результатов через поле, так что несколько подписей не нужны для разных типов методов.Спасибо, Морис!

Окончательное решение: В дополнение к тому, что мне не понравилась обязательная двойная стоимость отправки шаблона посетителя, я также хотел избежать переполнения интерфейса перегрузки foo(), но яне думайте, что для этого существует известный чистый шаблон.Я просто делал прямые статические перегрузки и назвал это днем.В любом случае, мое желание инкапсулировать перегрузку внутри функции, вероятно, в лучшем случае сомнительная цель.Спасибо, Морис за ответ.

1 Ответ

3 голосов
/ 31 августа 2010

На самом деле, интерфейсы не должны дублироваться. Подклассы посетителя могут обрабатывать детали операции. В вашем случае:

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;
    }
}

Итак, в каждом классе необходим только один метод accept ().

Все альтернативы шаблону посетителя, о которых я могу подумать, включают какой-то поиск во время выполнения, так что да, ИМХО, шаблон посетителей является самым быстрым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...