Re: Various template approaches to avoid pointer to function penalty
StephQ a ?crit :
and call the integration routine with:
integrate(myfunc(),10);
First question: what is myfunc() ? An object of type myfunc? Why?
I would have used:
myfunc f;
integrate(f, 10);
Named object used to prevent optimization. Perhaps this is a legacy.
Personnaly, I prefer integrate(myfunc(),10); because then I remember the
object is passed by value.
So myfunc() just calls the default constructor and the created obj is
passed to integrate.
I don' t understand why you say that from the syntax you remember that
the object is passed by value.
I could have defined the template function integrate this way too to
use pass by reference:
template<class Fo>
double integrate(const Fo& f, int n) { //instead of (Fo f, int n)
....
sum += f(i/n);
....
};
integrate(myfunc(),10);
It is STL deformation I presume.
...class can also carry traits which is not the case with function.
This is useful for object function composition.
For object function composition you mean when, for example, you call
the sort algorithm and use different comparison criteria right?
I mean composing binary function object with not2(), compose2(), plus(), ...
D) A more general apporach:
Suppose myclass is a class with member funcions f1 f2 (as usual double
double)
template<class fclass, double (flcass::*fun1)(double),
double(fclass::*fun2)(double)>
double integrate(int n, const fclass& fc) {
....
sum += (fc.*fun1)(i/n) + (fc.*fun2)(i/n);
....
};
The only reason you would want to pass a reference of fclass would be to
be able to use a derived class but the standard specifies function
object can be copied and then you have slicing.
Let say you pass it by value.
I use pass by reference because I want to avoid copying the object, as
the copy operation could be time expensive if the object is big.
Is there good reasons to use pass by value instead? (I don't have
conversion problems....)
How would you have defined integrate in this situation?
Yes, here it is possible. Again STL polution.
But then, I would have used accumulate() template with a functor parameter.
template<typename T>
struct add_mean : public binary_function<T,T,T>
{
const size_t n;
add_mean(size_t number):n(number){}
T operator() (const T& sum, const T& x) const{return sum+x/n;}
};
accumulate (v.begin(),v.end(),0.0,add_mean<double>(v.size()));
myclass mc;
integrate<myclass, &myclass::f1, &myclass::f2>(10, mc);
I understand this approach is more general: not only I choose the
class, but also I can choose the functions of the class that I'm using
in integrate.
This approach doesn't add anything. If you need to compose a class
operation, the better is to do it in a function that can be called.
And if you think about implmenting all functions in a single class and
then be able to chose the member function to use, that is a design I
would avoid (I would even refactor a code to avoid it).
I don't understand what you mean here.
Suppose we write an algorithm for finding the maximum of a function
that uses the function and the first derivative of the function.
We can define a class containing the function parameters as private
data, and the function and the first derivative of the function as
public member functions of the class.
We can then call the alg for any of these classes.
We let the user select the name of f and f' in the classes because
probably these names have particular meanings depending on the
"object" that these classes represents.
Is there a better way to accomplish this task?
It is a way to it but not in the case you mentioned in the OP where the
accumulating function was:
sum += (fc.*fun1)(i/n) + (fc.*fun2)(i/n);
in this case, it is likely to be more efficient (I would have to test to
be sure) and more maintainable to define a functor that return double
operator(double sum, double i){return sum+fc.fun1(i/n)+fc.fun2(i/n)}.
However, I find it strange to define a template taking adapation to the
member function to call; it is not a clear design in THIS case.
I would rather require an adaptor
template<typename ARG, typename RET>
struct derivable_function
{
//traits
RET function(const ARG& x);
RET derivative(const ARG& x);
};
An then, for each case:
struct myclass_derivation: public derivable_function<double,double>
{
const myclass& fun;
myfunc(const myclass& obj):fun(obj){}
double function(const double& x){return fun.f1(x);}
double derivative(const double& x){return fun.f2(x);}
}
Michael