I am playing with std::bind
and rvalue references, but I still don't figure out how it works, I have the following code:
class Dog {
public:
Dog(const string &name) : name_(name) {
cout << "Dog::ctor" << endl;
}
string GetName() {
return name_;
}
private:
string name_;
};
auto bind_fun = bind([](Dog &&d){ cout << d.GetName() << endl; }, Dog("DogABC"));
bind_fun();
When commenting out bind_fun()
, or if the lambda takes Dog&
rather than Dog&&
, the code run fine with expected output. When bind_fun()
is left uncommented, the following compile time error:
test3.cpp:109:3: error: no matching function for call to object of type 'std::__1::__bind<<lambda at test3.cpp:108:17>, Dog>'
f();
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/functional:1749:9: note: candidate template ignored: substitution failure [with _Args = <>]: implicit instantiation of undefined template
'std::__1::__bind_return<<lambda at test3.cpp:108:17>, std::__1::tuple<Dog>, std::__1::tuple<>, false>'
operator()(_Args&& ...__args)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/functional:1758:9: note: candidate template ignored: substitution failure [with _Args = <>]: implicit instantiation of undefined template
'std::__1::__bind_return<const <lambda at test3.cpp:108:17>, const std::__1::tuple<Dog>, std::__1::tuple<>, false>'
operator()(_Args&& ...__args) const
^
1 error generated.
My questions are:
- Why
bind_fun()
can not be called(won't compile) when the lambda takes rvalue reference? - What is the difference between using reference and rvalue reference as arguments for the lambda here?
The specification for std::bind
is rather dense. In brief, a plain bound argument (not a bind expression, not a reference_wrapper
, and not a placeholder) is passed to the bound function as std::forward<Vi>(tid)
where Vi
is TiD cv &
, cv
is the cv-qualifiers of the call wrapper, TiD
is the type decay_t<Ti>
, Ti
is the type actually passed to bind
, and tid
is "an lvalue of type TiD
constructed from std::forward<Ti>(ti)
", and ti
is the argument passed to bind
.
Applying this to your call, we see that Ti
is Dog
and ti
is Dog("DogABC")
. So TiD
is also Dog
, and Vi
is cv Dog &
, which means that std::forward<Vi>(Tid)
is an lvalue, and the compiler complains because your lambda takes an rvalue reference parameter, and an rvalue reference parameter cannot bind to a lvalue.
来源:https://stackoverflow.com/questions/26315604/stdbind-bind-lambda-with-rvalue-reference-as-argument