我有一个纯虚拟模型界面
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
,因为所使用的算法对于两种类型都是完全相同的,并且它将是代码的巨大重复。
答案 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::variant
或boost::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;
};