我发现了一篇非常有趣的文章 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>(); }
答案 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;
};
原始实现更为通用,但这保留了基本概念,但更简单