访问者和模板化虚拟方法

Tho*_*ews 10 c++ templates virtual-functions operator-overloading visitor

访问者模式的典型实现中,类必须考虑基类的所有变体(后代).在许多情况下,访问者中的相同方法内容应用于不同的方法.在这种情况下,模板化的虚拟方法将是理想的,但目前,这是不允许的.

那么,可以使用模板化方法来解析父类的虚方法吗?

鉴于(基础):

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);
  }
};
Run Code Online (Sandbox Code Playgroud)

现在奠定了基础,这里是踢球者的用武之地(模板化方法):

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

故意,在方法声明Visitor_Cout中不包含关键字virtual.方法签名的所有其他属性都与父声明(或可能是规范)匹配.

总体而言,此设计允许开发人员实现常见的访问功能,这些功能仅根据目标对象(接收访问的对象)的类型而有所不同.上面的实现是我在派生的访问者实现没有实现可选方法时发出警报的建议.

这是否符合C++规范?

(当有人说它适用于编译器XXX时,我不相信.这是一个反对一般语言的问题.)

Edw*_*nge 6

哦,我明白你在追求什么.尝试这样的事情:



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!"; }
};
Run Code Online (Sandbox Code Playgroud)

也就是说,你应该研究非循环访客模式.它误解了构建在框架中的访问者,因此您不必为您永远不会调用的内容实现函数.

有趣的是,我实际上使用了与此类似的东西来构建一个类型列表的非循环访问者.我应用了一个元函数,它基本上构建了Funky_Visitor_Base并将一个运算符(像我显示的那样带有apply()的东西)变成了一个完整列表的访问者.对象是反射性的,因此apply()本身实际上是一个基于它所击中的任何类型构建的元函数.实际上很酷很奇怪.

  • 我的示例具有虚拟函数,因为它是访问者。CRTP 与其说是一种模式,不如说是一种习惯用法,您会发现它在许多模式的实现中很有用。不知道为什么我被告知要谷歌搜索 CRTP:\...? (2认同)