2016-01-19 31 views
6

Rozważmy następujący fragment kodu:std :: wiążą i odniesienie RValue

class Widget{ 
}; 

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

return 0; 
} 

i wywołuje błąd

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

I moje pytanie brzmi: dlaczego pojawił się błąd? Wszakże robię wyraźną obsadę dla odniesienia rvalue - mam na myśli std::move(w) i biorę argument przez referencję rvalue - mam na myśli Widget&& ref.

Co słychać?

Ponadto poniższe prace kod, co mnie martwi tym bardziej:

class Widget{ 
}; 

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

return 0; 
} 

Odpowiedz

7

To może stać się wyraźniejsze, jeśli zanotować co std::bind schematycznie robi.

// 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 
} 

Ponieważ można wywołać obiekt funkcyjny std::bind daje wiele razy, że nie można „wykorzystać” zrobionego argumentem tak zostanie on przekazany jako lwartością odniesienia. Fakt, że sam przekazujesz wartość bind oznacza, że ​​nie ma kopii wykonanej na linii, gdzie zainicjowano a.

Jeśli spróbujesz skompilować swój przykład ze schematem bind pokazanym powyżej, otrzymasz także bardziej przydatny komunikat o błędzie z kompilatora.

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 
1

Aby to działało musisz napisać to tak:

#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; 
} 

Moje kompilator jest gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC)

+1

Twój przykład nie działa. Spróbuj zadzwonić do f(); – Gilgamesz

+0

Jak się zorientowałeś, że ten przykład nie działa? Z powodzeniem skompilowałem go z moim kompilatorem. Z jakiego kompilatora korzystasz? – zaratustra

+0

http://ideone.com/tl8tc3 – Gilgamesz