是否可以通过运行时多态执行双重调度?
说我有一些类,其中一些类可以加/乘/等等,我想将那些动态存储在另一个在运行时执行类型擦除的类中。然后说我想对该类中保存的数据执行基本操作。
(据我所知)处理此问题的方法是使用双重分派来专门化操作。但是,我遇到的所有解决方案都依赖于这样的事实,即您有许多类型,然后使用虚拟函数调用或dynamic_cast
,if-else
和RTTI在运行时推断类型。因为直到运行时才知道类中保存的数据,所以我无法创建一堆虚拟方法或对类型进行强力检查。因此,我认为访问者模式将是最好的解决方案,但是即使那样,我似乎也无法确定这是否可行。
我有一个包装器类,其中包含一个指向嵌套多态类的智能指针,以实现类型擦除和运行时多态性,但是我不知道是否可以使用访问者模式对此进行双重调度。 / p>
请注意,下面的代码不完整,仅显示了我的思考过程。
class Wrapper {
private:
class Concept;
template<typename T> class Model;
class BaseVisitor {
public:
virtual ~Visitor() = default;
virtual void visit(Concept &) = 0;
};
template<typename T>
class Visitor : public BaseVisitor {
private:
T first_;
public:
Visitor(T first) : first_(first) {}
virtual void visit(Concept &other) override {
// perform addition
}
};
class Concept {
public:
virtual ~Concept() = default;
virtual void add(Concept &m) const = 0;
virtual void accept(BaseVisitor &visitor) const = 0;
};
template<typename T>
class Model final : public Concept {
private:
T data_;
public:
Model(T m)
: data_(m) {}
virtual void add(Concept &m) const override {
Visitor<T> v(data_);
m.accept(v);
};
virtual void accept(BaseVisitor &visitor) const override {
visitor.visit(*this);
};
};
std::shared_ptr<const Concept> ptr_;
// This isn't right, it just illustrates what I'm trying to do.
// friend Something operator+(Wrapper &lhs, Wrapper &rhs) {
// return (*lhs.ptr_).add(*rhs.ptr_);
// }
public:
template<typename T>
Wrapper(T value) : ptr_(std::make_shared<Model<T>>(value)) {}
};
我已经研究过使用函数指针,模板专门化和静态类型ID来实现双重分发,但是我似乎无法弄清楚如何使其工作。
这甚至可能吗?
基于下面的评论,为了更具体并提供更多背景知识,我正在使用模板化类,该类使用模板函数执行基本操作(如加法和乘法)。但是,我也想将那些模板化的类存储在向量中,因此可以擦除类型。现在,如果要在执行类型擦除后对那些类进行操作,则需要某种方式来推断模板化函数的类型。但是,由于我无法轻松地从Wrapper
中获取内部保留类型,因此我希望有一种方法可以对Wrapper::Model<T>
类中保存的数据调用正确的模板函数,是访问者模式,静态类型ID还是什么。
更具体地说,我正在使用类进行延迟求值和符号计算,这意味着我拥有诸如Number<T>
之类的类,可以是Number<int>
,Number<double>
等以及诸如Variable
,Complex<T>
之类的类以及用于各种操作的所有TMP组合,诸如Add<Mul<Variable, Variable>, Number<double>>
等
我可以在编译时处理所有这些问题,但随后我需要将它们存储在向量中-类似于std::vector<Wrapper> x = {Number<int>, Variable, Add<Number<double>, Variable>};
。我对此的最佳猜测是执行类型擦除以将表达式存储在多态Wrapper
中。这具有双重职责,可以启用对符号表达式的运行时解析支持。
但是,我编写的用于处理加法的函数,例如
template<typename T1, typename T2>
const Add<T1, T2> operator+(const T1 &lhs, const T2 &rhs)
{ return Add<T1, T2>(lhs, rhs); }
不能接受Wrapper
并将其拉出(由于类型擦除)。但是,我可以将Wrapper
插入Add
表达式类中,这意味着我可以携带隐藏的类型。问题是当我真正开始评估诸如Add<Wrapper, Wrapper>
之类的结果时。为了知道结果如何,我需要弄清楚里面到底有什么,或者按照双重调度的方式做些什么。
主要问题是,与我的问题like this question on SO最接近的双重调度示例依赖于这样的事实,即我可以写出所有类,例如Shapes
,{{ 1}}。由于我无法明确地执行此操作,因此我想知道是否存在一种方法可以根据上面Rectangles
类中保存的数据执行两次分派以评估表达式。