Home > Back-end >  std::function argument to receives any number of arguments
std::function argument to receives any number of arguments

Time:12-02

I've defined a template function that receives std::function. and I want to send a member function. that works fine (example: test2) How can I rewrite it so std::function receives any number of argument? (test3)

another question - can this be done without the std::bind?

struct Cls
{
    int foo() { return 11; }
};

template<typename T>
void test2(std::function<T()> func)
{}

template<typename T, typename... Args> 
void test3(std::function<T(Args... args)> func, Args&&... args)
{}

int main()
{
    Cls ccc;

    test2<int>(std::bind(&Cls::foo, ccc));  // Ok
    test3<int>(std::bind(&Cls::foo, ccc));  // does not compile!
}

This is the error I receive:

no matching function for call to ‘test3<int>(std::_Bind_helper<false, int (Cls::*)(), Cls&>::type)’ 34 | test3<int>(std::bind(&Cls::foo, ccc));

CodePudding user response:

The issue is that std::bind doesn't return a std::function, it returns some unspecified callable type. Therefore the compiler can't deduce the correct template parameters for test3.

The way to work around that is to make your function accept any callable type instead of trying to accept a std::function:

template <typename Func, typename... Args>
void test3(Func&& func, Args&&... args)
{}

This will work with a std::bind result, a lambda, a raw function pointer, a std::function, etc.


can this be done without the std::bind?

Sort of. A pointer to a member function always requires an instance of the class to be called on. You can avoid needing to explicitly std::bind the instance into a wrapper by passing it as a parameter and using the std::invoke helper to call the function. For pointers to member functions, std::invoke treats the first parameter as the object to call the member on.

For example:

struct Cls
{
    int foo() { return 11; }
};

template <typename Func, typename... Args>
void test3(Func&& func, Args&&... args)
{
    std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
}

void bar(double, int) {}

int main()
{
    Cls ccc;

    test3(bar, 3.14, 42);  // Works with a raw function pointer
    test3(&Cls::foo, ccc); // Works with a pointer to member function
    test3([](int){}, 42);  // Works with other callable types, like a lambda
}

Demo

CodePudding user response:

can this be done without the std::bind?

Yes this can be done without std::bind as shown below.

struct Cls
{
    int foo() { return 11; }

    int func(int, double)
    {
        return 4;
    }
};


template<typename className, typename... Param,typename Ret, typename... Args>  
void test4(Ret (className::*ptrFunc)(Param... param),className& Object, Args... args)
{
    (Object.*ptrFunc)(args...);

    //std::invoke(ptrFunc, Object, args...); //WITH C  17

}
int main()
{
    Cls ccc;

   
    test4(&Cls::foo, ccc); //works 
    test4(&Cls::func, ccc, 4,5); //works 
}

Working demo

  •  Tags:  
  • c
  • Related