Посетитель и шаблонные виртуальные методы

В типичной реализации Шаблона "посетитель" класс должен составлять все изменения (потомки) базового класса. Существует много экземпляров, где то же содержание метода в посетителе применяется к различным методам. Шаблонный виртуальный метод был бы идеален в этом случае, но на данный момент, это не позволяется.

Так, шаблонные методы могут использоваться для разрешения виртуальных методов родительского класса?

Данный (основа):

struct Visitor_Base; // Forward declaration.

struct Base
{
  virtual accept_visitor(Visitor_Base& visitor) = 0;
};

// More forward declarations
struct Base_Int;
struct Base_Long;
struct Base_Short;
struct Base_UInt;
struct Base_ULong;
struct Base_UShort;

struct Visitor_Base
{
  virtual void operator()(Base_Int& b) = 0;
  virtual void operator()(Base_Long& b) = 0;
  virtual void operator()(Base_Short& b) = 0;
  virtual void operator()(Base_UInt& b) = 0;
  virtual void operator()(Base_ULong& b) = 0;
  virtual void operator()(Base_UShort& b) = 0;
};

struct Base_Int : public Base
{
  void accept_visitor(Visitor_Base& visitor)
  {
     visitor(*this);
  }
};

struct Base_Long : public Base
{
  void accept_visitor(Visitor_Base& visitor)
  {
     visitor(*this);
  }
};

struct Base_Short : public Base
{
  void accept_visitor(Visitor_Base& visitor)
  {
     visitor(*this);
  }
};

struct Base_UInt : public Base
{
  void accept_visitor(Visitor_Base& visitor)
  {
     visitor(*this);
  }
};

struct Base_ULong : public Base
{
  void accept_visitor(Visitor_Base& visitor)
  {
     visitor(*this);
  }
};

struct Base_UShort : public Base
{
  void accept_visitor(Visitor_Base& visitor)
  {
     visitor(*this);
  }
};

Теперь, когда начало положено, вот то, где строка над заголовком входит (шаблонные методы):

struct Visitor_Cout : public Visitor_Base
{
  template <class Receiver>
  void operator() (Receiver& r)
  {
     std::cout << "Visitor_Cout method not implemented.\n";
  }
};

Намеренно, Visitor_Cout не содержит ключевое слово virtual в объявлении метода. Все другие атрибуты сигнатур методов соответствуют родительскому объявлению (или возможно спецификация).

В большом изображении этот дизайн позволяет разработчикам реализовывать общую функциональность посещения, которая отличается только типом целевого объекта (объект, получающий посещение). Реализация выше является моим предложением для предупреждений, когда полученная реализация посетителя не имеет, реализуют дополнительный метод.

Действительно ли это законно спецификацией C++?

(Я не доверяю, когда некоторые говорят, что это работает с компилятором XXX. Это - вопрос против общего языка.)

10
задан Dave Schweisguth 14 February 2016 в 00:04
поделиться

2 ответа

о, я понимаю, что вам нужно. Попробуйте что-то вроде этого:



template < typename Impl >
struct Funky_Visitor_Base : Visitor_Base
{
  // err...
  virtual void operator()(Base_Int& b) { Impl::apply(b) }
  virtual void operator()(Base_Long& b) { Impl::apply(b) }
  virtual void operator()(Base_Short& b) { Impl::apply(b) }
  virtual void operator()(Base_UInt& b) { Impl::apply(b) }
  virtual void operator()(Base_ULong& b) { Impl::apply(b) }

  // this actually needs to be like so:
  virtual void operator()(Base_UShort& b)
  {
    static_cast<impl *const>(this)->apply(b) 
  }
};

struct weird_visitor : Funky_Visitor_Base<weird_visitor>
{
  // Omit this if you want the compiler to throw a fit instead of runtime error.
  template < typename T >
  void apply(T & t)
  {
    std::cout << "not implemented.";
  }

  void apply(Base_UInt & b) { std::cout << "Look what I can do!"; }
};

Тем не менее, вам следует изучить шаблон ациклического посетителя. Он неправильно понимает посетителей, встроенных в структуру, поэтому вам не нужно реализовывать функции для вещей, которые вы никогда не вызовете.

Забавно то, что я фактически использовал нечто очень похожее на это, чтобы построить ациклического посетителя для списка типов. Я применил метафункцию, которая в основном создает Funky_Visitor_Base и превращает оператор (что-то с функцией apply (), как я показываю) в посетителя для этого полного списка. Объекты являются отражающими, поэтому сам метод apply () на самом деле является метафункцией, которая строится на основе любого типа, с которым она сталкивается. На самом деле довольно круто и странно.

6
ответ дан 4 December 2019 в 02:25
поделиться

В производном классе посетителей, Visitor_Cout , шаблон operator () не переопределяет оператор operator () в Visitor_Base . Согласно стандарту C ++ 03 (14.5.2 / 4):

Специализация шаблона функции-члена не отменяет виртуальную функцию из базового класса. [Пример:

class B {
    virtual void f(int);
};

class D : public B {
    template <class T> void f(T);  // does not override B::f(int)
    void f(int i) { f<>(i); }      // overriding function that calls
                                   // the template instantiation
};

—конечный пример]

2
ответ дан 4 December 2019 в 02:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: