如何处理虚拟模板函数,其中模板参数的数量在C++中是已知的

How to deal with virtual template functions where the number of template arguments is known in C++?

本文关键字:参数 C++ 何处理 处理 函数 虚拟      更新时间:2023-10-16

>我有一个纯虚拟模型接口

class ModelInterface {
public:
  virtual ~ModelInterface() {}
  virtual double get_value(double scaleFactor) = 0;
};

这需要所有派生模型来实现get_value()函数。模型实现可能如下所示

class Model : public ModelInterface {
public:
  Model(double value) : _value(value) {}
  double get_value(double scaleFactor) {
    return _value * scaleFactor;
  }
private:
  double _value;
};

在主例程的开头,使用指向模型的接口指针创建并处理模型

int main ()
{
  ModelInterface *model = new Model(5.3);

在其他一些点,该模型用于计算所需的值

  double scale_factor = 2.2;
  double value = model->get_value(scale_factor);
  // do something with the value
  return 0
}

现在我需要将函数double get_value(double scaleFactor)中的类型 double 替换为其他一些数字类型,在这种情况下,可以处理自动微分,我们称之为 adouble 。但是,我仍然需要双重版本。有时我需要导数,那么应该用adouble类型调用该函数。如果我不需要派生信息,我想调用 double 类型的函数以节省资源。我希望能够做类似的事情

double scale_factor1;
double value1 = model->get_value(scale_factor1);
adouble scale_factor2;
adouble value2 = model->get_value(scale_factor2);

我的第一个意图是添加一个模板参数到行virtual double get_value(double scaleFactor) = 0;,这样template <class T> virtual T get_value(T scaleFactor) = 0;,但是GCC告诉我不允许虚拟模板。我发现的下一个解决方案是使整个虚拟类模板化,而不仅仅是函数,例如

template <class T>
class ModelInterface {
public:
  virtual ~ModelInterface() {}
  virtual T get_value(T scaleFactor) = 0;
};

但这并不能解决我的问题,因为我只有一个模型实例化,并且此实例化将绑定到双精度或双精度(或任何其他类型(,但我不能调用具有不同参数类型的同一对象的get_value()函数。

我还遇到了相当复杂的结构,包括助手和访客,以及任何应该能够解决一般问题的东西。但是,我怀疑我的情况是否有任何简单的解决方案,因为我想使用的不同类型的数量是固定的(2(,并且类型也是已知的(doubleadouble(。当然,我想避免为每种类型实现两次函数get_value(),因为两种类型使用的算法完全相同,这将是代码的巨大副本。

我建议您有一个带有重载的接口,但在实现中将通用代码放入模板中:

class ModelInterface {
public:
  virtual ~ModelInterface() {}
  virtual double get_value(double scaleFactor) = 0;
  virtual adouble get_value(adouble scaleFactor) = 0;
};
class Model : public ModelInterface {
public:
  Model(double value) : _value(value) {}
  double get_value(double scaleFactor) {
    return get_value_impl(scaleFactor);
  }
  adouble get_value(adouble scaleFactor) {
    return get_value_impl(scaleFactor);
  }
private:
  template<typename T> T get_value_impl(T scaleFactor) {
    return _value * scaleFactor;
  }
  double _value;
};

在您的特定情况下,我将在 base 中有两个纯虚函数(一个用于 double,一个用于 adouble (,它们只会将计算转发到每个子类中的模板化实现。

作为其他建议的替代方案 - 考虑使用 boost::variantboost::any

在您的界面中定义我们将使用变体值类型:

class ModelInterface {
public:
    virtual ~ModelInterface() {}
    using value = boost::variant<double, adouble>;
    virtual value get_value(value scaleFactor) const = 0;
};

并使用boost::static_visitor实现您的模型:

class Model : public ModelInterface {
public:
    Model(double val) : value_visitor(val) {}
    virtual value get_value(value val) const {
         return boost::apply_visitor(value_visitor, val);
    }
private:
    struct impl : boost::static_visitor<ModelInterface::value>
    {
          impl(double value) : value_(value) {}
          double value_;
          template <typename T>
          value operator()(T val) const
          {
              return static_cast<T>(val * value_);
          }
    };
    impl value_visitor;
};