Reputation: 61
I am writing a numerical library and I have some algorithms that are based on functions and their derivatives. These have to be provided by the user as functors, e.g.
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...
Now the declaration of my algorithm is e.g.:
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...
};
With all of the STL using templated algorithms and al the fuss about template programming in C++11 I felt really modern and cool using templates. However, what bugs me now is that in order to use this algorithm a user has to write all template arguments explicitly:
//construct functors
Algorithm<Function, DerivativeX, DerivativeY> alg( f, fx, fy);
(Imagine there were 6 derivatives. That's a lot to write) Second it's not possible to choose the set of functions (derivatives) at runtime so I am thinking of using Inheritance over templates.
I have two questions: First, do you think it is a good idea to use inheritance in this case, or are there other design patterns I could use?
Second, I am unfortunately not very experienced with the use and pitfalls of inheritance in a library so could you maybe show or explain how it is properly done for this case?
Edit: so after some research I can come up with
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);
as a possible implementation. Now, all the users will have to write their functions deriving from my library class and take good care that f fx and fy are still in scope when calling someFancyComputation. Is this good practice or is this considered restrictive? I also feel very uncomfortable with the raw pointers in this code, isn't there a better way to implement this?
Upvotes: 0
Views: 80
Reputation: 2623
In C++, you have many tools...
Template are appropriates when the algorithm is selected at compile-time.
Virtual functions are appropriate for run-time selection.
And there are also many other possibilities in between like std::function
, function pointers, member function pointers.
Also, you can replace your constructor call by a make_something
function (similar to those in standard library like make_unique
, make_shared
, make_pair
...). By the way, I think that constructor template deduction is planned for a coming standard.
So essentially, if the user select function to use in the algorithm, you have to use a solution based on run-time polymorphism. If the selection is made at compile-time, then the choice is your. Template based solution might be faster as the compiler could optimize that specific case. However, not in all cases it would be useful as it might also increase code size if you have many algorithms used in the same program.
Assuming that someFancyComputation
is not trivial and you want to apply the algorithm to either user selection or many compile-time types (like DerivativeX,Y, Z...
) solution based on inheritance (or other alternative mentioned above) would be preferable particularily if your algorithm only need to works with doubles.
You could also mixes both approaches as appropriate if some part are dynamic and other static (like maybe using long double
).
Upvotes: 3