在Modern C ++中定义访问者内联替换

时间:2014-12-01 11:00:46

标签: c++ c++11 design-patterns

我发现了一篇非常有趣的文章 Defining Visitors Inline in Modern C++

提出的解决方案虽然相当复杂。

我想知道是否有更简单的方法来解决这种情况?

下面添加了

代码和示例,以避免需要关注链接。

  

以文章为例,给出以下几个类:

struct Triangle; 
struct Square;

struct PolygonVisitor 
{ 
  virtual ~PolygonVisitor() {}

  virtual void visit(Triangle& tr) = 0;  
  virtual void visit(Square& sq) = 0;
};

struct Polygon 
{ 
  virtual void accept(PolygonVisitor& v) = 0;  
};

struct Triangle : Polygon 
{ 
  void accept(PolygonVisitor& v) override 
  {   
    v.Visit(*this); 
  }   
};

struct Square : Polygon 
{ 
  void accept(PolygonVisitor& v) override 
  {
    v.Visit(*this); 
  }   
};
     

构建内联访问者并使用它来计算出多少边   形状有:

int CountSides(Polygon& p)
{ 
  int sides = 0;

  auto v = begin_visitor<PolygonVisitor>()
    .on<Triangle>([&sides](Triangle& tr)
    {
       sides = 3;
    })
    .on<Square>([&sides](Square& sq)
    {
      sides = 4;
    })
    .end_visitor();

  p.Accept(v);
  return sides;
}
     

内联访问者定义如下(代码取自   https://github.com/jbcoe/inline_visitor):

template <typename T, typename F, typename BaseInnerVisitor, typename ArgsT>
class ComposeVisitor
{
 public:
  class InnerVisitor : public BaseInnerVisitor
  {
  public:
    using BaseInnerVisitor::Visit;
    typedef typename BaseInnerVisitor::VisitorInterface VisitorInterface;

    InnerVisitor(ArgsT&& args)
        : BaseInnerVisitor(std::move(args.second)), m_f(std::move(args.first))
    {
    }

    void Visit(T& t) final
    {
      VisitImpl(t);
    }

  private:
    template <typename F_ = F>
    typename std::enable_if<
        std::is_assignable<std::function<void(T&)>, F_>::value>::type
    VisitImpl(T& t)
    {
      m_f(t);
    }

    template <typename F_ = F>
    typename std::enable_if<std::is_assignable<
        std::function<void(T&, VisitorInterface&)>, F_>::value>::type
    VisitImpl(T& t)
    {
      m_f(t, *this);
    }

    F m_f;
  };

  ComposeVisitor(ArgsT&& args) : m_args(std::move(args))
  {
  }

  template <typename Tadd, typename Fadd>
  ComposeVisitor<Tadd, Fadd, InnerVisitor, std::pair<Fadd, ArgsT>>
  on(Fadd&& f) &&
  {
    return ComposeVisitor<Tadd, Fadd, InnerVisitor, std::pair<Fadd, ArgsT>>(
    std::make_pair(std::move(f), std::move(m_args)));
  }

  template <typename InnerVisitor_ = InnerVisitor>
  typename std::enable_if<!std::is_abstract<InnerVisitor_>::value,
                      InnerVisitor>::type
  end_visitor() &&
  {
    return InnerVisitor(std::move(m_args));
  }

  ArgsT m_args;
};


template <typename TVisitorBase>
class EmptyVisitor
{
 public:
  class InnerVisitor : public TVisitorBase
  {
  public:
    using TVisitorBase::Visit;
    typedef TVisitorBase VisitorInterface;
    InnerVisitor(std::nullptr_t)
    {
    }
  };

  template <typename Tadd, typename Fadd>
  ComposeVisitor<Tadd, Fadd, InnerVisitor, std::pair<Fadd, std::nullptr_t>>
  on(Fadd&& f) &&
  {
    return ComposeVisitor<Tadd, Fadd, InnerVisitor,
                          std::pair<Fadd, std::nullptr_t>>(
        std::make_pair(std::move(f), nullptr));
  }
};


template <typename TVisitorBase>
EmptyVisitor<TVisitorBase> begin_visitor()
{
  return EmptyVisitor<TVisitorBase>();
}

1 个答案:

答案 0 :(得分:1)

解决此问题的一种可能方法是从抽象访问者(示例中为PolygonVisitor)继承一个新类(InlineVisitor),该类为其实现的每个抽象方法接受其构造函数std :: function。

每个抽象方法都是根据std :: function stored

实现的
#include <functional>
#include <iostream>

struct Triangle;
struct Square;
struct PolygonVisitor
{
    virtual ~PolygonVisitor() {}
    virtual void visit(Triangle& tr) = 0;
    virtual void visit(Square& sq) = 0;
};

struct Polygon {
    virtual void accept(PolygonVisitor& v) = 0;
};

struct Triangle : Polygon
{
    void accept(PolygonVisitor& v) override { v.visit(*this); } 
};

struct Square : Polygon
{
    void accept(PolygonVisitor& v) override { v.visit(*this); }
};


class InlineVisitor : public PolygonVisitor
{
    public:
        virtual void visit(Triangle& value) { triangleFx_(value); }
        virtual void visit(Square& value)   { squareFx_(value); }

        std::function<void(Triangle&)> triangleFx_;
        std::function<void(Square&)>   squareFx_;

        InlineVisitor(const std::function<void(Triangle&)> triangleFx, 
                      const std::function<void(Square&)>   squareFx)
            : triangleFx_(triangleFx)
            , squareFx_(squareFx) {}
};

int countSides(Polygon& p)
{
    int sides = 0;
    InlineVisitor countSidesVisitor([&sides](Triangle& tr) { sides = 3; }, 
                                    [&sides](Square& sq)   { sides = 4; });
    p.accept(countSidesVisitor);
    return sides;
}

int main(int argc, char *argv[])
{
    Triangle t;
    Square s;
    std::cout << "sides of Triangle: " << countSides(t) << std::endl
              << "sides of Square: "   << countSides(s) << std::endl;
    return 0;
};

原始实现更为通用,但这保留了基本概念,但更简单