我正在编写一个数值库,我有一些基于函数及其导数的算法。这些必须由用户作为仿函数提供,例如
struct Function{
double operator()(double x, double y){return x*x+y*y);}
};
struct DerivativeX{
double operator()(double x, double y){return 2*x);}
};
//more derivatives...
现在我的算法声明如下:
template<class F, class F_X, class F_Y>
struct Algorithm
{
Algorithm( F f, F_X fx, F_Y fy):f_(f), fx_(fx), fy_(fy){}
double someFancyComputation( double input) {
//call f_(double,double), fx_(double,double) and fy_(double,double);
private:
F f_;
F_X fx_;
F_Y fy_;
//more other stuff...
};
所有的 STL 都使用模板化算法,并且在 C++11 中对模板编程大惊小怪,我觉得使用模板非常现代和酷。 然而,现在让我烦恼的是,为了使用这个算法,用户必须显式地编写所有模板参数:
//construct functors
Algorithm<Function, DerivativeX, DerivativeY> alg( f, fx, fy);
(假设有 6 个导数。要写的东西很多) 其次,不可能在运行时选择函数集(派生函数),因此我正在考虑在模板上使用继承。
我有两个问题: 首先,您认为在这种情况下使用继承是个好主意,还是我可以使用其他设计模式?
其次,不幸的是,我对库中继承的使用和陷阱不是很有经验,所以您能否展示或解释在这种情况下如何正确完成继承?
编辑:所以经过一些研究我可以想出
struct aBinaryFunction{
double operator()( double x, double y) = 0;
~aBinaryFunction(){}
};
struct Algorithm{
Algorithm( aBinaryFunction* f, aBinaryFunction* fx, aBinaryFunction* fy):f_(f), fx_(fx), fy_(fy){}
double someFancyComputation( double input) {
//call *f_(double,double), *fx_(double,double) and *fy_(double,double);}
private:
aBinaryFunction * f_, fx_, fy_;
//more other stuff...
};
//in main create functors and then call
Algorithm alg(f,fx,fy);
作为一个可能的实现。现在,所有用户都必须编写从我的库类派生的函数,并在调用 someFancyComputation 时小心确保 f fx 和 fy 仍在范围内。这是好的做法还是被认为是限制性的?我对这段代码中的原始指针也感到很不自在,难道没有更好的实现方式吗?
最佳答案
在 C++ 中,你有很多工具......
在编译时选择算法时,模板是合适的。
虚函数适用于运行时选择。
还有许多其他的可能性,如
std::function
、函数指针、成员函数指针。此外,您可以使用
make_something
函数(类似于标准库中的函数,如make_unique
、make_shared
来替换构造函数调用,make_pair
...). 顺便说一句,我认为构造函数模板推导计划用于即将到来的标准。
所以本质上,如果用户选择要在算法中使用的函数,则必须使用基于运行时多态性的解决方案。如果选择是在编译时进行的,那么选择权在您手中。基于模板的解决方案可能会更快,因为编译器可以优化特定情况。但是,并非在所有情况下它都有用,因为如果您在同一程序中使用许多算法,它也可能会增加代码大小。
假设 someFancyComputation
不是微不足道的,并且您想将该算法应用于用户选择或许多编译时类型(如 DerivativeX,Y, Z...
) 基于继承(或上面提到的其他替代方案)的解决方案将是更可取的,特别是如果你的算法只需要使用 double 。
如果某些部分是动态的而其他部分是静态的(比如可能使用 long double
),您也可以适本地混合使用这两种方法。
关于c++ - 使用仿函数模板或继承库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45253651/