0

Observe the following example:

#include <iostream>
#include <functional>
#include <cstdlib>

void Print_Wrapper(std::function<void(int)> function);
void Print(int param);

int main(){

  Print_Wrapper(Print);

  return EXIT_SUCCESS;
}

void Print_Wrapper(std::function<void(int)> function){
  int i = 5;
  function(i);
}
void Print(int param){
  std::cout << param << std::endl;
}

This works correctly, and prints 5.


Now look at the same example with an overloaded function added:

#include <iostream>
#include <functional>
#include <cstdlib>

void Print_Wrapper(std::function<void(int)> function);
void Print(int param);
void Print(float param);

int main(){

  Print_Wrapper(Print);

  return EXIT_SUCCESS;
}

void Print_Wrapper(std::function<void(int)> function){
  int i = 5;
  function(i);
}
void Print(int param){
  std::cout << param << std::endl;
}
void Print(float param){
  std::cout << param << std::endl;
}

This gives the following compiler error:

main.cpp:11:22: error: cannot resolve overloaded function ‘Print’ based on conversion to type ‘std::function’
Print_Wrapper(Print);

Could some explain why the compiler can't resolve the overload?
Print_Wrapper only expects an int function-- the float function shouldn't even be considered.


Additionally, what should I do to fix this?

I recall problems like this occurring if a typename or something was left out, but then that would require me to make Print_Wrapper a template.
Does Print_Wrapper need to be a function template?

I guess I'm use to functionality similar to this, that just works. For example:

#include <iostream>
#include <vector>
#include <cstdlib>

void Print_Wrapper(std::vector<int> param);
void Print(std::vector<int> param);
void Print(std::vector<float> param);

int main(){

  std::vector<int> vi{1,2,3};
  std::vector<float> vf{1.0,2.0,3.0};

  Print(vi); //prints int
  Print(vf); //prints float

  Print_Wrapper(vi); //prints int (no overload issue)
  Print_Wrapper(vf); //compiler error (as expected)

  return EXIT_SUCCESS;
}

void Print_Wrapper(std::vector<int> param){
  Print(param);
  return;
}
void Print(std::vector<int> param){
  std::cout << "int" << std::endl;
}
void Print(std::vector<float> param){
  std::cout << "float" << std::endl;
}

So I think the issue lies somewhere in the lookup rules of an actual C++ function, as this example only uses types. Thoughts?

Trevor Hickey
  • 36,288
  • 32
  • 162
  • 271

2 Answers2

6

In C++11, std::function's constructor can take any callable object, even when that is ill-formed and it cannot call the object. In C++14, overload resolution is fixed but both functions can be called with int so both are valid candidates.

You need to explicitely request the correct function:

Print_Wrapper(static_cast<void(*)(int)>(Print))
StenSoft
  • 9,369
  • 25
  • 30
  • Are you saying my example would work for C++14? – Trevor Hickey Apr 23 '15 at 00:12
  • This solution works. Without the cast, it still didn't work in C++14. – Trevor Hickey Apr 23 '15 at 00:14
  • Hmm, originally I though it should work in C++14 but after careful examination of [LWG 2132](https://cplusplus.github.io/LWG/lwg-defects.html#2132), the issue is present even in C++14 because both can be called with `int`. – StenSoft Apr 23 '15 at 00:39
  • There is no easy way to say "this conversion is a preferred user-defined conversion to some other conversion" as far as I can tell. Maybe with an unused varargs pack? Seems dirty. – Yakk - Adam Nevraumont Apr 23 '15 at 01:53
  • It is possible to prefer non-converting functions by declaring overloaded version of `Print_Wrapper`: `void Print_Wrapper(void(*func)(int)) { Print_Wrapper(std::function(func)); }` – StenSoft Apr 23 '15 at 08:27
3

You can assign both functions to std::function<void(int)> as both can be called with an int.

To force selecting correct overload with int version: Print_Wrapper(static_cast<void(*)(int)>(Print));

yachoor
  • 929
  • 1
  • 8
  • 18