This is a followup question to my previous question.
#include
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {retu
At the beginning, please let me introduce 2 key points:
a: When using nested std::bind, the inner std::bind is evaluated first, and the return value will be substituted in its place while the outer std::bind is evaluated. That means std::bind(f, std::bind(g, _1))(x)
executes as same as f(g(x))
does. The inner std::bind is supposed to be wrapped by std::ref if the outer std::bind wants a functor rather than a return value.
b: The r-value reference cannot be correctly forwarded to the function by using std::bind. And the reason has already been illustrated in detail.
So, let's look at the question. The most importance function here might be func_wrapper which is intended to perform 3 purposes:
According to point b, purpose 1 cannot be fulfilled. So, let's forget perfect forwarding and doit function template has to accept a l-value reference parameter.
According to point a, purpose 2 will be performed by using std::ref.
As a result, the final version might be:
#include
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {return 3;};
int something(int a) {return a;};
};
template auto func(C&& c) -> decltype(c()) { return c(); }
template int doit(C&/*&*/ c) // r-value reference can't be forwarded via std::bind
{
return c();
}
template void func_wrapper(C&& c)
{
func(std::bind(doit,
/* std::forward(c) */ // forget pefect forwarding while using std::bind
std::ref(c)) // try to pass the functor itsself instead of its return value
);
}
int main(int argc, char* argv[])
{
// call with a function pointer
func(foo);
func_wrapper(foo); // error disappears
// call with a member function
bar b;
func(b);
func_wrapper(b);
// call with a bind expression
func(std::bind(&bar::something, b, 42));
func_wrapper(std::bind(&bar::something, b, 42)); // error disappears
// call with a lambda expression
func( [](void)->int {return 42;} );
func_wrapper( [](void)->int {return 42;} );
return 0;
}
But, if you really want to achieve purpose 1 and 2, how? Try this:
#include
#include
void foo()
{
}
struct bar {
void operator()() {}
void dosomething() {}
};
static bar b;
template
void run(Executor&& e)
{
std::cout << "r-value reference forwarded\n";
e();
}
template
void run(Executor& e)
{
std::cout << "l-value reference forwarded\n";
e();
}
template
auto func(Executor&& e) -> decltype(e())
{
return e();
}
template
struct dispatcher_traits {
enum { value = b };
};
template
class dispatcher {
private:
static void dispatch(Executor& e, dispatcher_traits)
{
run(e);
}
static void dispatch(Executor& e, dispatcher_traits)
{
run(std::ref(e));
}
public:
static void forward(Executor& e)
{
dispatch(e, dispatcher_traits());
}
};
template
void func_wrapper(Executor&& e)
{
typedef dispatcher::value>
dispatcher_type;
func(std::bind(&dispatcher_type::forward, std::ref(e)));
}
int main()
{
func_wrapper(foo); // l-value
func_wrapper(b); // l-value
func_wrapper(bar()); // r-value
func_wrapper(std::bind(&bar::dosomething, &b)); // r-value
func_wrapper([](){}); // r-value
}
Let me explain some points: