Reputation: 21510
I have read many posts about variadic templates and std::bind but I think I am still not understanding how they work together. I think my concepts are a little hazy when it comes to using variadic templates, what std::bind is used for and how they all tie together.
In the following code my lambda uses the dot operator with objects of type TestClass but even when I pass in objects of type std::ref they still work. How is this exactly? How does the implicit conversion happen?
#include <iostream>
using std::cout;
using std::endl;
#include <functional>
#include <utility>
using std::forward;
class TestClass {
public:
TestClass(const TestClass& other) {
this->integer = other.integer;
cout << "Copy constructed" << endl;
}
TestClass() : integer(0) {
cout << "Default constructed" << endl;
}
TestClass(TestClass&& other) {
cout << "Move constructed" << endl;
this->integer = other.integer;
}
int integer;
};
template <typename FunctionType, typename ...Args>
void my_function(FunctionType function, Args&&... args) {
cout << "in function" << endl;
auto bound_function = std::bind(function, args...);
bound_function();
}
int main() {
auto my_lambda = [](const auto& one, const auto& two) {
cout << one.integer << two.integer << endl;
};
TestClass test1;
TestClass test2;
my_function(my_lambda, std::ref(test1), std::ref(test2));
return 0;
}
More specifically, I pass in two instances of a reference_wrapper with the two TestClass
objects test1
and test2
, but when I pass them to the lambda the .
operator works magically. I would expect that you have use the ::get()
function in the reference_wrapper to make this work but the call to the .integer
data member works..
Upvotes: 9
Views: 625
Reputation: 30605
It is important to note that with std::bind
;
The arguments to
bind
are copied or moved, and are never passed by reference unless wrapped instd::ref
orstd::cref
.
The "passed by reference" above is achieved because std::ref
provides a result of std::reference_wrapper
that is a value type that "wraps" the reference provided.
std::reference_wrapper
is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (likestd::vector
) which cannot normally hold references.
By way of an example of what bind
's unwrapping of the reference does (without the bind
);
#include <iostream>
#include <utility>
#include <functional>
int main()
{
using namespace std;
int a = 1;
auto b = std::ref(a);
int& c = b;
cout << a << " " << b << " " << c << " " << endl; // prints 1 1 1
c = 2;
cout << a << " " << b << " " << c << " " << endl; // prints 2 2 2
}
Upvotes: 0
Reputation: 41301
The reference unwrapping is performed by the result of std::bind()
:
If the argument is of type
std::reference_wrapper<T>
(for example,std::ref
orstd::cref
was used in the initial call tobind
), then the referenceT&
stored in the bound argument is passed to the invocable object.
Corresponding standardese can be found in N4140 draft, [func.bind.bind]/10.
Upvotes: 5