C++11 std::function and perfect forwarding

c++, c++11, perfect-forwarding, std-function

Solution

Perfect forwarding only works when the function itself (in this case `operator()`) is templated and the template arguments are deduced. For `std::function`, you get the `operator()` argument types from the template parameters of the class itself, which means they'll never be deduced from any arguments.

The whole trick behind perfect forwarding is the template argument deduction part, which, together with reference collapsing, is what perfect forwarding is.

I'll just conveniently link to my other answer about `std::forward` here, where I explain how perfect forwarding (and `std::forward`) works.

Note that `std::function`'s `operator()` doesn't need perfect forwarding, since the user himself decides what the parameters should be. This is also the reason why you cannot just add `&&` to `operator()`; take this example:

void foo(int){}

int main(){
  // assume 'std::function' uses 'ArgTypes&&...' in 'operator()'
  std::function<void(int)> f(foo);
  // 'f's 'operator()' will be instantiated as
  // 'void operator()(int&&)'
  // which will only accept rvalues
  int i = 5;
  f(i); // error
  f(5); // OK, '5' is an rvalue
}

Problem

Why definition of std::function<>::operator() in the C++ standard is: ``` R operator()(ArgTypes...) const; ``` and not ``` R operator()(ArgTypes&&...) const; ``` ? One would think that to correctly forward parameters, we need the && and then use `std::forward<ArgTypes>...` in the function body when forwarding the call? I partially reimplemented std::function to test this and I found out that if I use the &&, I get "cannot bind 'xxx' lvalue to 'xxx&&'" from g++ when I try later to pass parameters by value to operator(). I thought that I got enough grasp of the rvalue/forwarding concepts, but still I cannot grok this point. What am I missing?

Original source

Related problems