具有模板化返回值的虚拟模板函数解决方法

时间:2016-07-29 13:44:52

标签: c++ templates visitor

关于必须虚拟的模板化函数的变通方法的问题在这里很常见,虽然我找不到任何有助于我的问题的东西,这是这个问题的一个简单变体:need a virtual template member workaround

提出的方法是使用类型擦除,从而产生非常简洁的解决方案。但是,如果我需要从visit()方法返回值,该怎么办? OP在他的问题中已经有了这个方面,但由于他从未使用过结果,因此在解决方案中被忽略了。

现在想象一下这段代码:

template <typename T>
class BaseVisitor {
  public:
    BaseVisitor();
    T visit(BaseVisited *visited);
    virtual ~BaseVisitor();
}


class BaseVisited {
  BaseVisited();
  template <typename T>
    virtual T accept(BaseVisitor<T> *visitor) { return visitor->visit(this); };
  virtual ~BaseVisited();
}

即使应用了类型擦除技巧,我们仍然需要accept()进行模板化。还有什么想法吗?

注意:我不能使用基类作为返回值,正如在SO的一些答案中所建议的那样,因为T也可以代表任何基类型(int,string等)。

1 个答案:

答案 0 :(得分:1)

你基本上有两个选择:

  1. accept()提供常见的返回类型,例如std::any或其前身boost::any。或者,如果您有一些有限数量的可能返回类型,std::variant / boost::variant。这样,成员函数不需要是模板 - 但调用者必须知道如何处理它。

  2. 将结果存储在Visitor对象中。你必须存储而不是返回它,但至少你可以保留类型。您可以使用Visitor Pattern处理此问题。我们可以让不同的访问者拥有不同的结果类型;他们只是在内部存储它们:

    // a void visitor
    struct ShapePrinter : IShapeVisitor
    {
        void visit(const Square&) override { std::cout << "Square"; }
        void visit(const Circle&) override { std::cout << "Circle"; }
    };
    
    // a double visitor
    struct ShapePerimeterComputer : IShapeVisitor
    {
        void visit(const Square& square) override { perimeter = 4. * square.sideLength; }
        void visit(const Circle& circle) override { perimeter = 2. * M_PI * circle.radius; }
    
        double perimeter = 0.;
    };