8

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?

Barry
  • 286,269
  • 29
  • 621
  • 977
RTempete
  • 245
  • 1
  • 4
  • 2
    But `std::function` has multiple constructors and multiple operator=. Including a move constructor that corresponds to the move operator=. – michalsrb Sep 13 '16 at 13:38
  • 2
    @michalsrb in his example `F&&` is not a r-value-reference – David Haim Sep 13 '16 at 13:58
  • 1
    The same question seems to have been asked here: https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/ozZQh6dEsiA – Chris Drew Sep 13 '16 at 14:28

1 Answers1

3

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).

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • but if that so, why does `std::function::assign` is deprecated in C++17 but the signature of the constructor is not changed? that means someone did put some thought on improving `std::function` API, yet, they left the copy-the-callable-constructor unchanged – David Haim Sep 13 '16 at 14:37