The function signature for std::bind()
is as follows:
template< class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );
So args
is a variadic template universal reference, if I understand correctly. The traditional template type deduction rules for universal references are as follows:
... and I think these rules would apply to each arg in args
individually, meaning that all lvalues passed into std::bind()
as an argument to the functor would be passed by reference. However this contradicts the program below:
#include <iostream>
#include <functional>
void function(int& n) {
n++;
}
int main() {
int n = 0;
auto functor = std::bind(function, n);
functor();
std::cout << n << std::endl; // 0, not 1.
return 0;
}
In order to get n
to be passed by reference, you must do so explicitly via std::ref(n)
, which really confuses me given what (little) I know about universal references and perfect forwarding. How does std::bind()
take anything by value when it uses universal references, which would otherwise consume lvalues as references?
It has almost nothing to do with the signature, it is a design choice. std::bind
must of course store all its bound arguments somehow and it stores them as values. The "universality" is only used to properly construct them - by move or copy.
std::ref
is also stored by value but due to its nature, the wrapped object is "stored" by reference.
std::thread
has exactly the same behaviour. One can argue that (move) constructing a copy by default is safer because both returned objects tend to outlive locals which are the likeliest to be captured.