【问题标题】:Virtual template function with templated return value workaround具有模板化返回值解决方法的虚拟模板函数
【发布时间】:2016-07-29 13:44:51
【问题描述】:

关于必须为虚拟的模板化函数的变通办法的问题在这里很常见,尽管我找不到任何有助于解决我的问题的方法,这是这个问题的一个简单变体: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 等)。

【问题讨论】:

  • 如果你不习惯封闭类型系统(例如std::variant&lt;&gt;)和类型擦除(例如boost::anyvoid*),你唯一的选择可能是throw T(...);而不是@ 987654329@

标签: c++ templates visitor-pattern


【解决方案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.;
    };
    

【讨论】:

  • 没有。 2. 在多线程环境下会产生奇妙的副作用,除非你锁定直到读取。
  • 我不能使用 C++17 也不能使用 Boost,但事实上我有一个自己的 Any 类应该在这里有所帮助。我会试试看效果好不好。
猜你喜欢
  • 2012-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 2018-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多