14

Let's consider the following piece of code:

class Widget{
};

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

return 0;
}

and it triggers error

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

And my question is: Why the error has appeared? After all, I do an explicit cast to rvalue reference – I mean std::move(w) and I take argument by rvalue reference – I mean Widget&& ref.

What's up?

Moreover the the below code works, what makes me worried the more:

class Widget{
};

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

return 0;
}
ildjarn
  • 62,044
  • 9
  • 127
  • 211
Gilgamesz
  • 4,727
  • 3
  • 28
  • 63

2 Answers2

15

It might become clearer if you write down what std::bind schematically does.

// 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 function object std::bind gives you multiple times, it cannot “use up” the captured argument so it will be passed as an lvalue reference. The fact that you pass bind itself an rvalue only means that there is no copy made on the line where a is initialized.

If you try to compile your example with the schematic bind shown above, you'll also get a more helpful 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
5gon12eder
  • 24,280
  • 5
  • 45
  • 92
3

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)

neshkeev
  • 6,280
  • 3
  • 26
  • 47
  • How did you figure out that this example doesn't work? I successfully compiled it with my compiler. What compiler do you use? – neshkeev Jan 19 '16 at 15:20
  • Sorry, I was confused with the naming of my procedures, GCC didn't tell me that there were two function to call. – neshkeev Jan 19 '16 at 16:25
  • It won't work if `Widget` has an explicit move ctor. My compiler is GNU C++ 8.3.0. – Cody Sep 13 '22 at 10:00