I'm trying to figure out how to pass an std
function as a parameter. Here is a brief example:
#include <cmath>
#include <functional>
#include <iostream>
void bar(const double v, std::function<int(int)> foo) {
std::cout << foo(v) << std::endl;
}
int main() {
bar(-23., std::abs);
}
This code fails to compile with a message no matching function for call to bar
, but everything works fine if remove the std
prefix. What's the deal?
std::abs()
is not just one function. It's many functions, it's an overload set (see eg here: https://en.cppreference.com/w/cpp/numeric/math/abs). Hence, you cannot take its address like this. And that's the reason you cannot pass it like this to other functions. Even if there was only one overload, most functions in the standard library cannot have their address taken. There are few exceptions only.
Next, std::function
is not the go-to type to be used always when you need to pass a callable to a function. std::function
is for when you need a type-erased callable. No problem when you do not understand what it means, you can forget about std::function
for now. By the time you actually need it, you will know what it's good for.
You can use a lambda expression:
template <typename F>
void bar(const double v, F&& foo) {
std::cout << foo(v) << std::endl;
}
int main() {
bar(-23., [](double a){ return std::abs(a);});
}
Note that [](auto a) { return std::abs(a); }
would work as well. It would result in a class with templated operator()
that gets instantiated when called. You cannot do the same with a function template, though.
If you want to avoid the template, you can use function pointers:
using func_t = double(*)(double);
void bar(const double v, func_t foo) {
std::cout << foo(v) << std::endl;
}
If you remove the std
prefix, then there is only one overload inherited from C: https://en.cppreference.com/w/c/numeric/math/abs. The others are added by C++. Note that this can have particularly bad consequences when combined with using namespace std;
.