Search code examples
c++templatesstd-function

Deducing template parameters from std::function


I'm writing a little class using a static template member function trying to map a std::function with its parameters :

class test
{
public:
    template <typename R, typename... Args>
    static double exec(std::function<R(Args...)> func, Args && ... args) {
        func(std::forward<Args>(args)...);
        // do something
        return 0.0;
    }
};

Supposing I have these trivial functions :

  • void f1() { ; }
  • int f2(int v) { return v; }
  • double f3(int v1, float v2) { return (double)v1 * (double)v2; }

I would like to call my test::exec function like this :

test::exec(f1);
test::exec(f2, 4);
test::exec(f3, 1, 3.14f);

I'm using Visual Studio and I get this error for the second case (f2) :

error C2672: 'test::exec': no matching overloaded function found
error C2784: 'double test::exec(std::function<_Ret(_Types...)>,Args &&...)': could not deduce template argument for 'std::function<_Ret(_Types...)>' from 'int (__cdecl *)(int)'

Nevertheless, it work if I specify the the types in the template signature : test::exec<int, int>(sq, 4); Obviously, I would like to avoid that. Also, I don't know how to formulate the call to f1 with this syntax.

Is it possible to achieve this goal without specifying the signature of the template parameters?


Solution

  • The compiler can't deduce the std:function arguments and return type, because you are not passing exec a std::function at all.


    Instead of a std::function, you can just make exec accept an arbitrary type of callable (which includes functions), and let the compiler deduce its signature:

    template <typename Func, typename... Args>
    static double exec(Func func, Args && ... args);
    

    If you do need to know the return type of the function that you pass to exec, you can do it like this:

    template <typename Func, typename... Args>
    static double exec(Func func, Args && ... args) 
    {
      using R = decltype(func(args...));
      // ...
    }
    

    The answer is adapted from @IgorTandetnik's comments.