2016-01-19 2 views
6

Considérons le morceau de code suivant:std :: bind et référence rvalue

class Widget{ 
}; 

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

return 0; 
} 

et déclenche l'erreur

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

Et ma question est: Pourquoi l'erreur est apparu? Après tout, je fais une distribution explicite à référence rvalue - je veux dire std::move(w) et je prends argument par référence rvalue - je veux dire Widget&& ref.

Quoi de neuf?

De plus, le travaux de code en dessous, ce qui me rend inquiet plus:

class Widget{ 
}; 

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

return 0; 
} 

Répondre

7

Il pourrait devenir plus clair si vous écrivez ce que std::bind-t schématiquement.

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

Comme vous pouvez appeler l'objet fonction std::bind vous donne plusieurs fois, il ne peut pas « utiliser jusqu'à » l'argument capturé il sera passé comme une référence lvalue. Le fait que vous passiez bind lui-même à un rvalue signifie seulement qu'il n'y a pas de copie faite sur la ligne où a est initialisé.

Si vous essayez de compiler votre exemple avec le schéma bind montré ci-dessus, vous obtiendrez également un message d'erreur plus utile de votre compilateur.

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

Pour ce faire, vous devez travailler écrire comme ceci:

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

Mon compilateur est gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC)

+1

Votre exemple ne fonctionne pas. Essayez d'appeler f(); – Gilgamesz

+0

Comment avez-vous compris que cet exemple ne fonctionne pas? Je l'ai compilé avec succès avec mon compilateur. Quel compilateur utilisez-vous? – zaratustra

+0

http://ideone.com/tl8tc3 – Gilgamesz