Является ли шаблон посетителя самым быстрым способом различения типов параметров в 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), что, насколько мне известно, невозможно с лестницами 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(), но я не думаю, что существует известный чистый шаблон. сделать это. Я закончил тем, что просто выполнял прямые статические перегрузки и положил на этом день. В любом случае, мое желание инкапсулировать перегрузку внутри функции, вероятно, в лучшем случае сомнительная цель. Спасибо, Морис за ответ.


person Jeff    schedule 31.08.2010    source источник
comment
для читателей после С++ 11: взгляните на библиотеку Yorel Multimethod (которая сейчас находится в Boost)   -  person Julien__    schedule 20.01.2016


Ответы (1)


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

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().

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

person Maurice Perry    schedule 31.08.2010
comment
Ах, хороший момент. Введение в вопрос и пример кода обновлены, чтобы отразить это. - person Jeff; 31.08.2010