Search code examples
c++stdstd-function

A problem passing functions from std as a function parameter


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?


Solution

  • 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;.