Std :: bind and rvalue reference

Consider the following code snippet:

class Widget{ }; int main(){ Widget w; auto lambda = bind([](Widget&& ref){ return; }, std::move(w)); return 0; } 

and it causes an error

 no match for call to '(std::_Bind<main()::<lambda(Widget&&)>(Widget)>) ()' lambda(); 

And my question is: why did the error appear? In the end, I am explicitly casting the rvalue link β€” I mean std::move(w) , and I am taking the argument of the rvalue link β€” I mean Widget&& ref .

What?

Also, the code below works, which makes me worry more:

 class Widget{ }; int main(){ Widget w; auto lambda = bind([](Widget& ref){ return; }, std::move(w)); return 0; } 
+7
c ++ c ++ 11 rvalue-reference
source share
2 answers

This can become clearer if you write that schematically std::bind .

 // C++14, you'll have to write a lot of boilerplate code for C++11 template <typename FuncT, typename ArgT> auto bind(FuncT&& func, ArgT&& arg) { return [ f = std::forward<FuncT>(func), a = std::forward<ArgT>(arg) ]() mutable { return f(a); }; // NB: a is an lvalue here } 

Since you can call the object of the std::bind function, you get it several times, it cannot "use" the captured argument, so it will be passed as an lvalue reference. The fact that you pass bind yourself to rvalue only means that there is no copy in the line where a is initialized.

If you try to compile your example with the bind scheme shown above, you will also get a more useful error message from your compiler.

 main.cxx: In instantiation of 'bind(FuncT&&, ArgT&&)::<lambda()> mutable [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]': main.cxx:10:33: required from 'struct bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]::<lambda()>' main.cxx:11:31: required from 'auto bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]' main.cxx:18:59: required from here main.cxx:11:26: error: no match for call to '(main()::<lambda(Widget&&)>) (Widget&)' ]() mutable { return f(a); }; // NB: a is an lvalue here ^ main.cxx:11:26: note: candidate: void (*)(Widget&&) <conversion> main.cxx:11:26: note: conversion of argument 2 would be ill-formed: main.cxx:11:26: error: cannot bind 'Widget' lvalue to 'Widget&&' main.cxx:18:33: note: candidate: main()::<lambda(Widget&&)> <near match> auto lambda = bind([](Widget&&){ return; }, std::move(w)); ^ main.cxx:18:33: note: conversion of argument 1 would be ill-formed: main.cxx:11:26: error: cannot bind 'Widget' lvalue to 'Widget&&' ]() mutable { return f(a); }; // NB: a is an lvalue here 
+8
source share

To make it work, you need to write it like this:

 #include <functional> #include <iostream> class Widget{}; int main() { Widget a; auto lf = [](Widget&& par){ }; auto f = std::bind ( lf, std::bind ( std::move<Widget&>, a ) ); f(); return 0; } 

My compiler is gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC)

+1
source share

All Articles