There are multiple ways to resolve this. First of all, you could convert to the appropriate function pointer type:
foo(static_cast<double(*)(double)>(sin));
However, this is unspecified behavior (possibly ill-formed), because sin
is not an addressable function.
It's perfectly fine to do this for your own functions, just not for functions in the standard library.
To be safe, you can wrap this function in a lambda expression:
foo([](double x) { return sin(x); }, 0.34);
Note on "lifting" functions frequently
It happens quite often that you have to "lift" standard library functions like this, so some people define a macro:
// TODO: perfect forwarding, conditional noexcept, ...
#define LIFT(...) [](auto &&...args) { return __VA_ARGS__(args...); }
foo(LIFT(sin), 0.34);
Note on reducing instantiations
[](double x) { return sin(x); }
denotes a unique closure type, so we are calling foo<CLOSURE, double>
. We might still want to call foo<double(*)(double), double>
instead, to save on instatiations.
The closure type defined by a lambda expression is implicitly convertible to a function pointer if the lambda expression has no captures.
You could explicitly cast to a double(*)(double)
, or pass +[](double x) ...
if you wanted to call foo
with a function pointer instead of the lambda expression.
Note on perfect forwarding
Your original foo
could be improved as follows:
template<class T, class F>
T foo(F &&f, T &&x){
return std::forward<F>(f)(std::forward<T>(x));
}
- forwarding
x
means that we possibly use the move constructor when calling f
- forwarding
f
means that we possibly use an rvalue-ref-qualified call operator (it's rare that this exists, but it theoretically can)