关于c ++:具有模板化返回值的虚拟模板函数

Virtual template function with templated return value workaround

关于必须是虚拟的模板化函数的解决方法的问题在这里很常见,尽管我找不到任何有助于解决我的问题的方法,这是这个问题的一个简单变体:需要一个虚拟模板成员解决方法

建议的方法是使用类型擦除,从而得到一个非常干净和简单的解决方案。但是,如果我需要从visit()方法返回一个值怎么办?这个操作在他的问题中已经有了这个方面,但是由于他从未使用结果,所以在解决方案中被忽略了。

现在想象一下这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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();
}

我们仍然需要使用EDOCX1[1]模板化,即使在应用了类型擦除技巧之后。还有什么想法吗?

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


你基本上有两个选择:

百万千克1

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

百万千克1百万千克1

将键入的结果存储在Visitor对象中。您必须存储它而不是返回它,但至少您可以保留该类型。您可以使用访问者模式来处理这个问题。我们可以让不同的访问者拥有不同的结果类型;他们只在内部存储它们:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 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.;
};

百万千克1