How do I refer to std::sin(const valarray<double> &)?

c++, function-pointers, functional-programming

Solution

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<T>`, but rather some 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 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 <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` so it returns `fp` again.

template<typename T>
T addy(T fp, id<T>) { 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<Y>(FN(std::valarray<Y>())))

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)));

Problem

I'm having trouble with some valarray function pointer code: ``` double (*fp)(double) = sin; valarray<double> (*fp)(const valarray<double> &) = sin; ``` The first compiles, the second gives: ``` error: no matches converting function 'sin' to type 'class std::valarray<double> (*)(const class std::valarray<double>&)' ```

Original source