I\'m having trouble with some valarray function pointer code:
double (*fp)(double) = sin;
valarray (*fp)(const valarray &) =
This compiles, using the __typeof__
GCC extension. Looks like GCC's valarray
uses expression templates to delay calculation of the sinus. But that will make the return type of the sin
template not exactly valarray
, but rather some weird complex type.
#include
template struct id { typedef T type; };
int main() {
using std::valarray;
using std::sin;
id<__typeof__(sin(valarray()))>::type (*fp)(const valarray &) = sin;
}
Edit: See AProgrammer's standard quote for why GCC is fine doing that.
Edit: Standard compliant workaround
Doing this without __typeof__
in a strictly Standard conforming way is a bit tricky. You will need to get the return type of sin
. You can use the conditional operator for this, as Eric Niebler has shown. It works by having the sin
function not actually called, but only type-checked. By trying to convert the other branch (the one which is actually evaluated) of the conditional operator to that same type, we can generate a dummy parameter just to be able to deduce the type of the function pointer:
#include
using std::valarray;
template struct id {
typedef T type;
};
struct ded_ty {
template
operator id() { return id(); }
};
template
id const&)> genFTy(T t) {
return id const&)>();
}
template
void work(T fp, id) {
// T is the function pointer type, fp points
// to the math function.
}
int main() {
work(std::sin, 1 ? ded_ty() : genFTy(std::sin(valarray())));
}
If you want to get the address right away, you can write work
so it returns fp
again.
template
T addy(T fp, id) { return fp; }
Now, you can finally write a macro to encapsulate the conditional operator trickery, and use it when you want to get the address of any such math function.
#define DEDUCE(FN,Y) (1 ? ded_ty() : genFTy(FN(std::valarray())))
To get the address and pass it to some generic function, the following works then
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)));