The std::function type erasure constructor is defined as:
template< class F >
function( F f );
The assignment operator is defined as:
template< class F >
function& operator=( F&& f );
(source cppreference)
Why does the constructor gets f by value while operator= gets f by forwarding reference?
I can only guess, but I would guess it is because it was added to C++ while rvalue references and forwarding references where being added to the language.
So some parts of its API got forwarding references, and some did not.
There is one minor advantage: if the copy constructor of F could throw while the move cannot, std::function( F ) can be guaranteed not to throw, while std::function( F const& ) cannot be. The difference is that the copy would be done outside the constructor in the template<class F> function(F) case, but inside the constructor in the template<class F> function(F&&) case when passed a non-rvalue.
This is not a compelling reason.
It would also make it marginally easier to specify the SFINAE behavior of function(F), but that wasn't formalized until long after C++11, so that cannot be the reason.
The cost to template<class F>function(F) is low -- one move of F over the perfect forwarding version -- so it probably hasn't been high on anyone's priority list to change (especially because it causes a subtle change in the "could throw" tests of function(F), and hence could actually in theory cause some strange code to break).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With