我认为具有通用引用参数的构造函数比没有引用的构造函数具有更好的性能。
From cppreference (https://en.cppreference.com/w/cpp/utility/functional/function/function), we can see that the template constructor for std::function is not using reference.
template< class F > function( F f );
Run Code Online (Sandbox Code Playgroud)
Is it a mistake? If not, why the standard doesn't requires the constructor use universal reference?
EDIT:
Let's think about two cases.
Using universal reference:
lvalue case: 4 bytes are copied.
rvalue case: 4 bytes are copied. (Will you apply a std::move to built-in type?)
Passing by value:
all cases: 4 bytes are copied.
std::string by value. This example stands for most cases, do you agree?Using universal reference:
lvalue case: copy constructor is invoked once
rvalue case: move constructor is invoked once
Passing by value:
lvalue case: a move and a copy
rvalue case: a move
Is this classification complete? If so, we can run into the conclusion that universal reference is no worse then passing by value. Then it returns to the original question.
EDIT again:
Maybe lambdas without captures are the most common cases, where passing by value is actually passing nothing while passing by reference is passing a pointer. This may be the key. LWG 2774 is related to this question. See it in comments.
Because that constructor moves its argument, accepting a reference is pointless. This comes down to the usual advice on when to take values.
If you pass a primitive, like an int, passing by reference is a pessimisation. If you pass a complex type, like a std::string, you can already std::move it into the argument (and, if you don't, then that's because you wanted a copy anyway). You get the best of both worlds.
// Bog-standard choice between value and ref; original value only observed
void foo(const int& x) { cout << x << '\n'; }
void foo(const int x) { cout << x << '\n'; } // Better!
void foo(const std::string& x) { cout << x << '\n'; } // Better!
void foo(const std::string x) { cout << x << '\n'; }
// When we want to store
void storeACopy(int);
void foo(const int& x) { storeACopy(x); }
void foo(const int x) { storeACopy(x); } // Better!
void storeACopy(std::string);
void foo(const std::string& x) { storeACopy(x); } // Meh
void foo(std::string x) { storeACopy(std::move(x)); } // Cheap!
// So, best of both worlds:
template <typename T>
void foo(T x) { storeACopy(std::move(x)); }
// This performs a copy when needed, but allows callsite to
// move instead (i.e. total flexibility) *and* doesn't require silly
// refs-to-primitives
Run Code Online (Sandbox Code Playgroud)
It also signals to the call site that the original object will not be modified unless you specifically yield ownership with std::move.
If instead the function took a reference, okay you'd potentially save one move if you want to yield. But, moves are supposed to be super-cheap so we're not concerned about that. And if you didn't want to yield then suddenly you have to go through the rigmaroll of an object copy at the callsite. Ugh!
This pattern is key to making the most out of move semantics.