Search code examples
c++functiontemplatesoverload-resolutiontemplate-argument-deduction

How to declare the template argument for an overloaded function


I have a fairly big project that, regarding this question, I can summarize with this structure:

void do_something()
{
    //...
}

template<typename F> void use_funct(F funct)
{
    // ...
    funct();
}

int main()
{
    // ...
    use_funct(do_something);
}

All is working ok until someone (me) decides to reformat a little minimizing some functions, rewriting as this minimum reproducible example:

void do_something(const int a, const int b)
{
    //...
}

void do_something()
{
    //...
    do_something(1,2);
}

template<typename F> void use_funct(F funct)
{
    // ...
    funct();
}

int main()
{
    // ...
    use_funct(do_something);
}

And now the code doesn't compile with error: no matching function for call where use_funct is instantiated.

Since the error message was not so clear to me and the changes were a lot I wasted a considerable amount of time to understand that the compiler couldn't deduce the template parameter because do_something could now refer to any of the overloaded functions.

I removed the ambiguity changing the function name, but I wonder if there's the possibility to avoid this error in the future not relying on template argument deduction. How could I specify in this case the template argument for do_something(), possibly without referring to a function pointer? I haven't the slightest idea to express explicitly:

use_funct<-the-one-with-no-arguments->(do_something);


Solution

  • You can wrap the function in a lambda, or pass a function pointer after casting it to the type of the overload you want to call or explicitly specify the template parameter:

    use_funct([](){ do_something (); });
    use_funct(static_cast<void(*)()>(do_something));
    use_funct<void()>(do_something);
    

    Wrapping it in a lambda has the advantage, that it is possible to defer overload resolution to use_func. For example:

    void do_something(int) {}
    
    void do_something(double) {}
    
    template<typename F> void use_funct(F funct) {   
        funct(1);    // calls do_something(int)
        funct(1.0);  // calls do_something(double)
    }
    
    int main() {   
        use_funct([](auto x){ do_something (x); });
    }
    

    [...] possibly without referring to a function pointer?

    I am not sure what you mean or why you want to avoid that. void() is the type of the function, not a function pointer. If you care about spelling out the type, you can use an alias:

    using func_type = void();
    use_funct<func_type>(do_something);