2012-08-01 9 views
15
//------------------------------------------------------------------------------ 
struct A 
{ 
    A(){} 
    A(A&&){} 
    A& operator=(A&&){return *this;} 
    void operator()(){} 

private: 
    A(const A&); 
    A& operator=(const A&); 

    int x; 
}; 

//------------------------------------------------------------------------------ 
int main() 
{ 
    A a; 
    std::function<void()> func(std::move(a)); 
} 

‚A :: A‘: kann nicht privat Mitglied in der Klasse erklärte Zugriff ‚A‘Warum kann C++ 11 einen nicht kopierbaren Funktor nicht in eine std :: -Funktion verschieben?

Es scheint, als wenn ich etwas mit Bezug zu erfassen oder const ich ein nicht-kopierbaren Lambda machen kann. Jedoch, wenn ich das tue, funktioniert es tatsächlich, es std::function zu geben.

+1

Als [Workaround] (https://gist.github.com/vmilea/5815777) könnten Sie einen kopierbaren Adapter zwischen std :: function und Ihrem Funktor einfügen. Der Adapter verfügt über einen Dummykopiekonstruktor (Kopie kopieren) und löst aus, wenn er kopiert wird. –

Antwort

19

Die kurze Antwort ist, dass die C++ 11 Spezifikation erfordert ACopyConstructible mit std::function verwendet werden.

Die lange Antwort ist diese Anforderung existiert, weil std::function den Typ Ihres Funktors innerhalb des Konstruktors löscht. Dazu muss std::function über virtuelle Funktionen auf bestimmte Mitglieder Ihres Funktors zugreifen. Dazu gehören der Aufrufoperator, der Kopierkonstruktor und der Destruktor. Und da diese über einen virtuellen Aufruf aufgerufen werden, werden sie "verwendet", unabhängig davon, ob Sie tatsächlich den Kopierkonstruktor, Destruktor oder Aufrufoperator von std::function verwenden.

+0

Korrigieren Sie mich, wenn ich falsch liege (und wahrscheinlich bin ich), aber, um virtuelle Funktionen zu verwenden, benötigen Sie eine vtable und damit eine Basisklasse. Welches ist die Basisklasse in diesem Fall? – akappa

+5

Siehe http://stackoverflow.com/questions/6324694/type-erasure-in-c-how-boostshared-ptr-and-boostfunction-work für eine Beschreibung, wie Typ löschen funktioniert. Die Basisklasse ist ein Implementierungsdetail von std :: function. Die abgeleitete Klasse ist ebenfalls ein Implementierungsdetail, wird aber auch auf dem bereitgestellten Funktor als Templates bereitgestellt. –

+0

sehr interessant, danke. – akappa

-1

Es ist ein Fehler in Visual Studio. Es versucht eine Kopie zu erstellen (wenn es eigentlich versuchen soll, eine Bewegung zu eliminieren), was einen barrierefreien Kopierkonstruktor erfordert. Die beste Lösung besteht darin, den Kopierkonstruktor/Zuweisungsoperator einfach zu deklarieren und niemals zu definieren. Die Klasse wird weiterhin nicht kopierbar sein, aber der Code wird kompiliert, weil VS niemals versuchen wird, den Kopierkonstruktor tatsächlich aufzurufen.

+3

Es versucht anscheinend, die Kopie ctor zu nennen, wenn ich tue, wie Sie vorschlagen, weil ich ein ungelöstes äußeres dafür erhalte. – David

+0

@Dave: Ja, deshalb ist es ein * Bug *. Der Standard sagt, dass es erlaubt sein sollte, aber VS macht es nicht richtig. –

+0

@ NicolBolas Das ist in Ordnung, aber sein Workaround-Vorschlag hat nicht funktioniert. Darf ich das nicht sagen? (Ich weiß die Antwort zu schätzen, obwohl DeadMG, danke) – David

Verwandte Themen