Search code examples
c++lambdaoverloadingoverload-resolutionstdbind

Getting function object for overload set


This code doesn't work, because &f creates a function pointer to only one of the the two f() functions, so the compiler doesn't know which one:

#include <iostream>
#include <string>

void f(int i) {
    std::cout << "f(int)" << std::endl;
}

void f(std::string str) {
    std::cout << "f(std::string)" << std::endl;
}

template<typename Callback>
void call(const Callback& callback) {
    callback(1);
    callback("a");
}

int main() {
    call(&f);
}

It works as intended if I instead make a template lambda function like

call([](const auto& arg) { f(arg); });

Is there a way to do this without writing an extra lambda, that needs to pass all the arguments? For example with a std::bind expression? Or is there a limitation in the language that the overload for f only gets resolved in a function call expression?


Solution

  • The function to be called can also be choosen via a static_cast:

    int main() {
        call(static_cast<void(*)(std::string)>(&f));
    }
    

    However, once you decided which overload to call it is either the int one or the std::string one.

    To call both callback(1); and callback("a"); you need the overload resolution at the function call (or later, but not before as above). And the easiest way to do that is to use the lambda.

    The lambda is conceptually similar to

     struct my_callable {
           template <typename T> 
           void operator()(const T& t) {
                  f(t); // <---- overload resolution kicks in here
           }
     };
    

    And you could achieve the same via

     struct my_callable2 {
         void f(int i) {
            std::cout << "f(int)" << std::endl;
         }
         void f(std::string str) {
            std::cout << "f(std::string)" << std::endl;
         }
     };
    

    However, the lambda is likely to be inlined, hence no real benefit of avoiding one function call is to be expected. And it wont get any less boilerplate by writing the functor yourself.