bind und rvalue-Referenzen
-
Hiho,
meine Frage möchte ich an folgendem Codebeispiel erläutern:
std::function<void(CSystemMessage&&, CMessageChannel*)> handler = std::bind(&CMessageServer::handleSystemMessage, this, std::placeholders::_1, std::placeholders::_2);oder mit boost:
boost::function<void(CSystemMessage&&, CMessageChannel*)> handler = boost::bind(&CMessageServer::handleSystemMessage, this, _1, _2);Wie man an der functtion sieht, soll ein Parameter ein rvalue sein. Die Methode handleSystemMessage hat genau die gewünschte Signatur:
void handleSystemMessage(CSystemMessage&& msg, CMessageChannel* pChannel);Das ganze endet in einer ziemlich langen Fehlermeldung vom Compiler. Hier nur ein kurzer Ausszug:
D:\libraries\cpp\boost\boost_1_55_0\boost/bind/bind.hpp(392): error C2664: 'void boost::_mfi::mf2<void,tuc::nw::CMessageServer,tuc::nw::CSystemMessage &&,tuc::nw::CMessageChannel *>::operator ()(T *,A1,A2) const' : Konvertierung von Argument 2 von 'tuc::nw::CSystemMessage' in 'tuc::nw::CSystemMessage &&' nicht möglich
Mache ich prinzipiell was falsch, oder kann bind das nicht, oder ist das ein Comnpiler/Bibliotheksproblem?
VG
Pellaeon
-
Der Code* ist mit**
std::**bindkorrekt, weilbindfür die Argumente perfect forwarding anwendet. Und ich bin mir sicher, dass Boost auch perfect forwarding nutzen sollte.Sieht nach der Fehlermeldung zu urteilen eher nach einem VC++-Bug aus.
~* Edit: Ich kenne den Code nicht, denke aber du definierst/verwendest alles entsprechend.~
-
Ob
std::binddas prinzipiell können soll (Argumente richtig forwarden), kann ich gerade nicht mit Sicherheit sagen. Da müsste ich mal im Standard nachgucken. Aber ich wäre stark überrascht, wenn das nicht klappen sollte. In dem Fall wäre die Standardbibliothek und/oder Compiler noch nicht auf dem aktuellen Stand. Boost.Bind würde ich das weniger zutrauen.ich frage mich aber, warum Du überhaupt noch
bindverwendest, wenn Du doch sowieso schon C++11 mit Rvalue-Referenzen und damit auch Lambdas voraussetzt.Probier mal:
std::function<void(CSystemMessage&&, CMessageChannel*)> handler = [this](CSystemMessage&& m, CMessageChannel* c) { this->handleSystemMessage(std::move(m),c); };
-
kkaw schrieb:
ich frage mich aber, warum Du überhaupt noch
bindverwendest, wenn Du doch sowieso schon C++11 mit Rvalue-Referenzen und damit auch Lambdas voraussetzt.Ob bind oder Lambda ist ja letztendlich Geschmackssache. Sollte beides zum Ziel führen. Wenn ich wirklich nur einen Aufruf durchleiten will, nehme ich einfach aus Gewohntheit bind. Sollen noch zusätzliche Aktionen/Befehle ausgeführt werden, dann wirds natürlich ein Lambda.
Hier nochmal ein Minimalbeispiel ohne meine Klassen:
// BindTest.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung. // #include "stdafx.h" //std includes #include <iostream> #include <functional> //boost includes #include <boost/bind.hpp> #include <boost/function.hpp> struct Foo { void foo(int&& i) { std::cout << i << std::endl; } }; int _tmain(int argc, _TCHAR* argv[]) { Foo myFoo; //boost -> compile error boost::function<void(int&&)> boostHandler = boost::bind(&Foo::foo, &myFoo, _1); //std -> compile error std::function<void(int&&)> stdHandler = std::bind(&Foo::foo, &myFoo, std::placeholders::_1); //lambda handler -> works fine std::function<void(int&&)> lambdaHandler = [&myFoo](int&& i) { myFoo.foo(std::move(i)); }; return 0; }std wie auch die boost-variante gehen bei mir im VS 2013 nicht.
-
Ohne Boost kompiliert das fehlerfrei - also falsche Implementierung in VC++'s Standardbibliothek. Kein Perfect Forwarding. Denn ohne Perfect Forwarding wird natürlich einfach ein lvalue übergeben:
R operator()(T * p, A1 a1) const { BOOST_MEM_FN_RETURN (p->*f_)(a1); // a1 ist *immer* ein lvalue, auch wenn A1 eine rvalue-Referenz ist. }Ich habe damit die Ursache für diese scheinbar unsinnige Fehlermeldung gefunden: Der Compiler beschwert sich, dass ein lvalue vom Typ
intinint&&konvertiert werden will. Das mit dem lvalue sagt aber nur GCC, Clang hat mich da verwirrt.
-
Warum verwendest du überhaupt eine rvalue-Referenz? Das macht man eigentlich nicht, wenn kein Template vorliegt.
-
Nimm das Objekt per LValue-Referenz entgegen.
-
Ist ein alter Bug, den ich mal entdeckt hatte. Der wird wohl erst in der kommenden VS-Version gefixt:
https://connect.microsoft.com/VisualStudio/feedback/details/717188/bug-concerning-rvalue-references-and-std-function-std-bind-in-vc11
-
Und keine C-Praefixe.