How can I refer to std :: sin (const valarray <double> &)?
I am having problems with some valarray function pointer code:
double (*fp)(double) = sin; valarray<double> (*fp)(const valarray<double> &) = sin; The first compilation, the second gives:
error: no matches converting function 'sin' to type 'class std::valarray<double> (*)(const class std::valarray<double>&)' Compiled using the __typeof__ GCC extension. GCC valarray use expression patterns to delay sine computation. But that will make the return type of the sin template not exactly valarray<T> , but rather some kind of weird complex type.
#include <valarray> template<typename T> struct id { typedef T type; }; int main() { using std::valarray; using std::sin; id<__typeof__(sin(valarray<double>()))>::type (*fp)(const valarray<double> &) = sin; } Edit: See the AProgrammer standard quote for why GCC does it perfectly.
Edit: Standards-compliant workaround
Doing this without __typeof__ strictly standard way is a bit complicated. You will need to get the return type sin . You can use the conditional operator to do this, as Eric Nibler showed. It works if the sin function is not actually called, but only checked for type. Having tried to convert another branch (the one that was actually evaluated) of the conditional operator to the same type, we can create a dummy parameter to be able to infer the type of the function pointer:
#include <valarray> using std::valarray; template<typename T> struct id { typedef T type; }; struct ded_ty { template<typename T> operator id<T>() { return id<T>(); } }; template<typename E, typename T> id<T(*)(valarray<E> const&)> genFTy(T t) { return id<T(*)(valarray<E> const&)>(); } template<typename T> void work(T fp, id<T>) { // T is the function pointer type, fp points // to the math function. } int main() { work(std::sin, 1 ? ded_ty() : genFTy<double>(std::sin(valarray<double>()))); } If you want to get the address right away, you can write work to return fp again.
template<typename T> T addy(T fp, id<T>) { return fp; } Now you can finally write a macro to encapsulate the deception of the conditional operator and use it when you want to get the address of any such mathematical function.
#define DEDUCE(FN,Y) (1 ? ded_ty() : genFTy<Y>(FN(std::valarray<Y>()))) To get the address and pass it to some common function, the following is done:
std::transform(v1.begin(), v1.end(), v1.begin(), addy(std::sin, DEDUCE(std::sin, double))); std::transform(v2.begin(), v2.end(), v2.begin(), addy(std::cos, DEDUCE(std::cos, double))); 26 3.1 / 3
Any function that returns valarray is allowed to return an object of another type, provided that all constant valarray functions are also applicable to this type.
The goal is to allow the use of template expressions to optimize the result (i.e., cyclic one-time execution of the entire array that performs a calculation each time, directly assigning the resulting valarray <> instead of creating a temporary one).
z = sin(x+y); can be optimized for
for (i = 0; i < N; ++i) z[i] = sin(x[i] + y[i]); You talk about std::sin in the header, but then assign ::sin .
valarray<double> (*fp)(const valarray<double> &) = std::sin; That should work. Note that you must qualify all uses of sin , although most implementations will enter a name in the global namespace, even if you include <cmath> (this is non-standard behavior).
Edit: Sorry, you're out of luck. The standard says about sin(valarray<T> const &) following (26.3.3.3).
This function returns a value that is of type T or can be uniquely converted to type T.
Optimizations performed by gcc are provided by the standard. Work on the code above is not guaranteed.