是否可以使用运行时多态性执行双重调度?
假设我有一些类,其中一些类可以添加/相乘/等等,我想将它们动态地存储在另一个在运行时执行类型擦除的类中。然后说我想对该类中保存的数据执行基本操作。
处理这个问题的方法(据我所知)是使用双重调度来专门化操作。但是,我遇到的所有解决方案都依赖于您拥有大量类型的事实,然后在运行时使用虚函数调用或dynamic_cast
s, if-else
, 和 RTTI 来推断类型。因为类中保存的数据直到运行时才知道,所以我无法创建一堆虚拟方法或对类型进行强力检查。所以我认为访问者模式将是最好的解决方案,但即便如此,我似乎也无法确定这是否可能。
我有一个包装类,它包含一个指向嵌套多态类的智能指针,以实现类型擦除和运行时多态,但我不知道是否可以使用访问者模式对此进行双重调度。
请注意,下面的代码是不完整的,它只是展示了我的思考过程。
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>>
, ETC。
我可以在编译时很好地处理所有这些,但是我需要能够将它们存储在一个向量中——比如std::vector<Wrapper> x = {Number<int>, Variable, Add<Number<double>, Variable>};
. 我对此的最佳猜测是执行类型擦除以将表达式存储在 polymorphicWrapper
中。这具有双重职责,以启用符号表达式的运行时解析支持。
但是,我编写的用于处理加法的函数,例如
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>
. 为了知道这是什么结果,我需要弄清楚里面到底是什么,或者按照双重调度的方式做一些事情。
主要问题是与我的问题最接近的双重分派示例,例如 SO 上的这个问题,依赖于我可以写出所有类的事实,例如Shapes
, Rectangles
。由于我不能明确地这样做,我想知道是否有一种方法可以执行双重调度,以根据Model<T>
上面类中保存的数据来评估表达式。