如何处理虚拟模板函数,其中模板参数的数量在C++中是已知的
How to deal with virtual template functions where the number of template arguments is known in C++?
>我有一个纯虚拟模型接口
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(,并且类型也是已知的(double
和adouble
(。当然,我想避免为每种类型实现两次函数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::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;
};
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 使用指向成员的指针将成员函数作为参数传递
- 没有名称的C++模板参数
- 如何将enable-if与模板参数和参数包一起使用