Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

std::abs is not one function. Its many functions, its an overload set (see eg here https://en.cppreference.com/w/cpp/numeric/math/abs). Hence, you cannot take its address like this. And thats 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 goto 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 its 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 funciton 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;.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading