C++ 在现代C+中定义内联访问者+;交替服用

C++ 在现代C+中定义内联访问者+;交替服用,c++,c++11,design-patterns,C++,C++11,Design Patterns,我发现了一篇非常有趣的文章 不过,提出的解决方案相当复杂 我想知道是否有更简单的方法来解决这个问题 下面添加了代码和示例,以避免需要遵循链接 以论文中的示例为例,给出以下类别: struct Triangle; struct Square; struct PolygonVisitor { virtual ~PolygonVisitor() {} virtual void visit(Triangle& tr) = 0; virtual void visit(S

我发现了一篇非常有趣的文章

不过,提出的解决方案相当复杂

我想知道是否有更简单的方法来解决这个问题

下面添加了代码和示例,以避免需要遵循链接

以论文中的示例为例,给出以下类别:

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;
}
int CountSides(多边形和多边形)
{ 
内边=0;
自动v=开始\访客()
.在([&边](三角形和tr)
{
侧面=3;
})
.在([&边](正方形和正方形)
{
侧面=4;
})
.end_visitor();
p、 接受(v);
返回侧;
}
内联访问者的定义如下(代码取自 ):

模板
类组合器
{
公众:
类InnerVisitor:public BaseInnerVisitor
{
公众:
使用BaseInnerVisitor::Visit;
typedef typename BaseInnerVisitor::VisitorInterface VisitorInterface;
InnerVisitor(ArgsT&&args)
:BaseInnerVisitor(std::move(args.second)),m_f(std::move(args.first))
{
}
无效访问(T&T)决赛
{
VisitImpl(t);
}
私人:
模板
typename std::启用\u如果<
std::is_assignable::value>::类型
VisitImpl(T&T)
{
m_f(t);
}
模板
typename std::enable_if::value>::type
VisitImpl(T&T)
{
m_f(t,*此);
}
F m_F;
};
组合浏览器(ArgsT&&args):m_args(std::move(args))
{
}
模板
分频器
打开(Fadd&f)&&
{
回程分频器(
std::make_pair(std::move(f),std::move(m_args));
}
模板
typename std::enable_if::value,
InnerVisitor>::类型
(完)&&
{
返回InnerVisitor(std::move(m_args));
}
ArgsT m_args;
};
模板
类空视野器
{
公众:
类InnerVisitor:公共TVisitorBase
{
公众:
使用TVisitorBase::Visit;
typedef TVisitorBase访问接口;
InnerVisitor(std::nullptr\t)
{
}
};
模板
分频器
打开(Fadd&f)&&
{
回程分频器(
std::make_pair(std::move(f),nullptr));
}
};
模板
清空访问者开始\访问者()
{
返回EmptyVisitor();
}

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

每个抽象方法都是根据存储的std::函数来实现的

#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;
};
#包括
#包括
结构三角形;
结构广场;
结构PolygonVisitor
{
虚拟~PolygonVisitor(){}
虚拟无效访问(三角形和tr)=0;
虚拟无效访问(平方和平方)=0;
};
结构多边形{
虚拟无效接受(PolygonVisitor&v)=0;
};
结构三角形:多边形
{
void accept(PolygonVisitor&v)重写{v.visit(*this);}
};
结构正方形:多边形
{
void accept(PolygonVisitor&v)重写{v.visit(*this);}
};
类InlineVisitor:公共PolygonVisitor
{
公众:
虚拟无效访问(三角形和值){triangleFx_ux(值);}
虚拟虚空访问(平方和值){squareFx_uz(值);}
std::函数triangleFx;
std::函数squareFx;
InlineVisitor(const std::函数triangleFx,
常量std::函数squareFx)
:triangleFx_Ux(triangleFx)
,squareFx_u2;(squareFx){}
};
整数边(多边形和多边形)
{
内边=0;
InlineVisitor countSidesVisitor([&sides](三角形&tr){sides=3;},
[&sides](正方形和正方形){sides=4;});
p、 接受(countSidesVisitor);
返回侧;
}
int main(int argc,char*argv[])
{
三角形t;
正方形s;

std::不能将相关上下文添加到您的问题中。不要指望您的听众点击此处的链接。我很想了解生成的汇编程序与手写访问者的比较。我们在设计中添加的复杂性都是为了消除生成的汇编程序的差异。
#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;
};