Why can't assign an overloaded function to std::function?

1
2
3
4
int add(int i, int j) { return i + j; }
std::string add(const std::string& s1, const std::string& s2) { return s1 + s2; }
...
std::function<int(int, int)> xxx = add;

I got an error:
cannot convert from 'overloaded-function' to 'std::function<int (int,int)>'
.

At first, I had thought that this is because the compiler is unable to select a best-match function among overloaded function candidates to match the template constructor of `std::function` class (link: https://en.cppreference.com/w/cpp/utility/functional/function/function):
1
2
template< class F >
function( F&& f );
where F is `int(int, int)` in my question so the concrete form of the constructor is `function( int (&& f)(int,int) );`

However, the following (correct) code shows that my first thought is incorrect:
1
2
3
4
5
int add(int i, int j) { return i + j; }
std::string add(const std::string& s1, const std::string& s2) { return s1 + s2; }
void test_func(int (&&f)(int,int)) { f(1,2); }
...
test_func(add);

The C++ compiler I use correctly selects the first `add` function to match the testing function with `int (&& f)(int,int)` parameter where the testing function acts as the constructor of `std::function` class.

From the above example, I think the compiler should be able to pick the first `add` function. But why the error when I tried to assign an overloaded function to a `std::function<int(int, int)>` variable in which the type of the function has already been clearly specified?
There is a constructor template and a class template in play here, and the <int(int, int)> in std::function<int(int, int)> xxx = add; is attached to the class template, not the constructor template.

To illustrate, this code exhibits the same problem:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void f(int) {}
void f(float) {}

template <int N> 
  struct my_class_template 
  { 
    template <typename F> 
      my_class_template(F&&) {}
  };

int main()
{
  // Attempt to call my_class_template<42>::my_class_template:
  my_class_template<42> o(f); // error: 
  // There is no way to determine which version of f is intended.
  // The "42" attaches to the class template's template parameter, not the
  // constructor template's template parameter.
}


There is no way to explicitly specify the template arguments of a constructor template.

In your case, you can work-around this limitation by adding a static_cast around the function name:
std::function<int(int, int)> xxx = static_cast<int(*)(int, int)>(add);
Alternatively you can use a lambda expression as follows:
std::function<int(int, int)> xxx = [](int a, int b) { return add(a, b); };
Last edited on
Registered users can post here. Sign in or register to post.