1

是否可以使用运行时多态性执行双重调度?

假设我有一些类,其中一些类可以添加/相乘/等等,我想将它们动态地存储在另一个在运行时执行类型擦除的类中。然后说我想对该类中保存的数据执行基本操作。

处理这个问题的方法(据我所知)是使用双重调度来专门化操作。但是,我遇到的所有解决方案都依赖于您拥有大量类型的事实,然后在运行时使用虚函数调用或dynamic_casts, 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和拉出类型(由于类型擦除)。但是,我可以将 插入WrapperAdd表达式类中,这意味着我可以携带隐藏类型。问题是当我真正开始评估类似Add<Wrapper, Wrapper>. 为了知道这是什么结果,我需要弄清楚里面到底是什么,或者按照双重调度的方式做一些事情。

主要问题是与我的问题最接近的双重分派示例,例如 SO 上的这个问题,依赖于我可以写出所有类的事实,例如Shapes, Rectangles。由于我不能明确地这样做,我想知道是否有一种方法可以执行双重调度,以根据Model<T>上面类中保存的数据来评估表达式。

4

0 回答 0