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