2016-01-19 12 views
6

Consideriamo il seguente pezzo di codice:std :: bind e riferimento rvalue

class Widget{ 
}; 

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

return 0; 
} 

e innesca l'errore

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

Ed è la mia domanda: perché è apparso l'errore? Dopotutto, faccio un cast esplicito a riferimento di rvalue - intendo lo std::move(w) e prendo argomento per riferimento di rvalue - intendo Widget&& ref.

Che succede?

Inoltre l'opere codice qui sotto, ciò che rende mi preoccupava più:

class Widget{ 
}; 

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

return 0; 
} 

risposta

7

Potrebbe diventare più chiaro se si scrive giù quello std::bind fa schematicamente.

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

Dal momento che si può chiamare l'oggetto funzione std::bind ti dà più volte, non può “consumare” l'argomento catturato in modo che venga passato come un riferimento lvalue. Il fatto che si passi bind stesso un rvalue significa solo che non è stata eseguita alcuna copia sulla riga in cui è inizializzato a.

Se si tenta di compilare il proprio esempio con lo schema bind mostrato in precedenza, si otterrà anche un messaggio di errore più utile dal compilatore.

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

Per farlo funzionare è necessario scrivere in questo modo:

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

mio compilatore è gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC)

+1

Il tuo esempio non funziona. Prova a chiamare f(); – Gilgamesz

+0

Come hai capito che questo esempio non funziona? L'ho compilato con successo con il mio compilatore. Che compilatore usi? – zaratustra

+0

http://ideone.com/tl8tc3 – Gilgamesz