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
}
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
}