如何处理C ++中已知模板参数数量的虚拟模板函数?

时间:2016-02-12 16:05:46

标签: c++ templates polymorphism

我有一个纯虚拟模型界面

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中的类型double get_value(double scaleFactor)替换为其他数字类型,在这种情况下可以处理自动区分,我们称之为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;
};

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

我还遇到了相当复杂的构造,包括帮助者和访问者以及应该能够解决一般问题的任何东西。但是我怀疑我的情况是否有任何简单的解决方案,因为我想要使用的不同类型的数量是固定的(2)并且类型是已知的(double和{{1 }})。当然,我想避免为每种类型实现两次函数adouble,因为所使用的算法对于两种类型都是完全相同的,并且它将是代码的巨大重复。

3 个答案:

答案 0 :(得分:3)

我建议你有一个带有重载的接口,但是在实现中将公共代码放入模板:

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;
};

答案 1 :(得分:1)

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

答案 2 :(得分:0)

作为其他提案的替代方案 - 请考虑使用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;
};