具有模板化 return 值解决方法的虚拟模板函数
Virtual template function with templated return value workaround
关于必须是虚拟的模板化函数的解决方法的问题在这里很常见,尽管我找不到任何可以帮助解决我的问题的问题,这是这个问题的一个简单变体:need a virtual template member workaround
建议的方法是使用类型擦除,从而获得非常干净和简单的解决方案。但是,如果我需要 return 来自 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()
进行模板化。还有其他想法吗?
注意:我不能使用基础 class 作为 return 值,正如在 SO 的一些答案中所建议的那样,因为 T 也可以代表任何基础类型(int , 字符串等).
你基本上有两个选择:
为 accept()
提供通用的 return 类型,例如 std::any
or its predecessor boost::any
。或者,如果您有一些有限数量的可能 return 类型,std::variant
/boost::variant
。这样,成员函数就不需要是模板——但调用者必须知道如何使用它。
将键入的结果存储在 Visitor
对象中。你必须存储它而不是 returning 它,但至少你可以保留类型。您可以使用 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.;
};
关于必须是虚拟的模板化函数的解决方法的问题在这里很常见,尽管我找不到任何可以帮助解决我的问题的问题,这是这个问题的一个简单变体:need a virtual template member workaround
建议的方法是使用类型擦除,从而获得非常干净和简单的解决方案。但是,如果我需要 return 来自 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()
进行模板化。还有其他想法吗?
注意:我不能使用基础 class 作为 return 值,正如在 SO 的一些答案中所建议的那样,因为 T 也可以代表任何基础类型(int , 字符串等).
你基本上有两个选择:
为
accept()
提供通用的 return 类型,例如std::any
or its predecessorboost::any
。或者,如果您有一些有限数量的可能 return 类型,std::variant
/boost::variant
。这样,成员函数就不需要是模板——但调用者必须知道如何使用它。将键入的结果存储在
Visitor
对象中。你必须存储它而不是 returning 它,但至少你可以保留类型。您可以使用 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.; };