std :: Funktion als benutzerdefinierter Stream-Manipulator

8

Ich versuche C ++ 11-Funktionen zu verwenden, um benutzerdefinierte Stream-Manipulatoren einfacher zu erstellen. Ich kann Lambda-Funktionen als Manipulatoren verwenden, aber nicht std::function<ostream&(ostream&)> .

Hier ist der gekürzte Code:

%Vor%

Die zweite cout -Anweisung schlägt mit folgendem fehl:

%Vor%

Warum scheitert das? Ich benutze cygwin gcc 4.5.3.

Während ich frage, bin ich nicht verrückt nach der Verwendung von std::function wegen der Effizienzprobleme. Aber ich möchte Funktionen schreiben, die Lambda-Funktionen zurückgeben und keine Ahnung haben, wie das geht, ohne std::function . Zum Beispiel wäre so etwas wie das Folgende toll.

%Vor%

... funktioniert aber offensichtlich nicht. Gibt es eine alternative Syntax, die funktioniert? Ich kann mir nicht vorstellen, was es sein könnte, also könnte ich bei std::function feststecken.

Wenn ich eine Lösung für die zweite Frage hätte, wäre die erste Frage fragwürdig.

Danke.

Definieren von operator<<(ostream&, std::function<ostream&(ostream&)> half. Ich hatte eine Webseite falsch gelesen und hatte den Eindruck, dass ostream schlau genug war, ein beliebiges Objekt mit einem operator() als Manipulator zu behandeln. Ich habe mich geirrt. Außerdem wurde das einfache lambda , das ich gebaut habe, wahrscheinlich nur zu einer einfachen alten Funktion kompiliert, genau wie mir gesagt wurde. In der Tat, wenn ich die Variable Capture verwenden, um sicherzustellen, dass lambda keine einfache Funktion ist, schlägt der Compiler fehl. Außerdem werden Objekte mit operator() (standardmäßig) nicht als Manipulatoren behandelt:

%Vor%

Weitere Aktualisierung: Es stellt sich heraus, dass eine etwas robustere Lösung als die folgenden mit:

erreicht werden kann %Vor%

Dieser Code hat ein zusätzliches const . Ich entdeckte dies, als ich versuchte, die Lösung in meinem Projekt zu implementieren.

    
Ed Krohne 22.10.2012, 00:35
quelle

3 Antworten

7

Wenn du operator<< für ostream betrachtest, gibt es keine Überladung für die Verwendung von std::function - und das ist im Grunde das, was du hier mit cout << functionManip machen willst. Um dies zu beheben, definieren Sie entweder die Überlast selbst:

%Vor%

Oder übergeben Sie stream als Argument an die Funktion:

%Vor%

Warum lambda funktioniert, da der Rückgabetyp von lambda nicht definiert ist und eine Überladung für die Verwendung eines Funktionszeigers besteht:

%Vor%

Das Lambda umschließt wahrscheinlich alles, indem es eine Struktur verwendet und operator() definiert, was in diesem Fall genau wie ein Funktionszeiger funktioniert. Das ist für mich die wahrscheinlichste Erklärung, hoffentlich kann mich jemand korrigieren, wenn ich falsch liege.

    
Yuushi 22.10.2012, 00:59
quelle
5

Dies ist nicht die Ursache des Fehlers, aber da Sie sowohl lambdaManip als auch functionManip mit dem Rückgabetyp ostream& definiert haben, glaube ich, dass Sie vergessen haben, return stream; zu beiden hinzuzufügen.

Der Aufruf cout << functionManip schlägt fehl, weil kein operator<<(ostream&, std::function<ostream&(ostream&)> definiert ist. Fügen Sie einen hinzu, und der Anruf wird erfolgreich ausgeführt.

%Vor%

Alternativ können Sie functionManip als

aufrufen %Vor%

Dies funktioniert, ohne die operator<< -Definition hinzuzufügen.

Wie bei Ihrer Frage zur Rückgabe eines Lambda kann das Lambda, das von getAdditionFunctor zurückgegeben wird, ein Capture-less Lambda sein, das implizit in einen Funktionszeiger umgewandelt werden kann.

%Vor%     
Praetorian 22.10.2012 01:00
quelle
3

Die vorherigen Antworten haben den neuesten Stand der Technik, aber wenn Sie schwer mit std::function s und / oder lambdas als Stream-Manipulatoren in Ihrem Code verwenden wollen, dann möchten Sie vielleicht nur Hinzufügen der folgenden Funktionsschablonendefinition zu Ihrer Codebase im globalen Bereich:

%Vor%

Der nachfolgende Rückgabetyp verwendet Ausdruck SFINAE , so dass diese besondere operator<< Überladung gewonnen hat Nehmen Sie nicht einmal an der Überladungsauflösung teil, es sei denn m(os) ist ein wohlgeformter Ausdruck. (Das ist was du willst.)

Dann kannst du sogar Dinge wie

tun %Vor%

(Beachten Sie das vollständige Fehlen von std::function -Objekten im obigen Code! Versuchen Sie, lambdas nicht in std::function -Objekte einzufüllen, es sei denn, Sie müssen dies unbedingt tun, da das Erstellen eines std::function -Objekts teuer sein kann Speicherzuweisung.)

Es wäre sinnvoll, wenn C ++ 17 diese operator<< overload der Standardbibliothek hinzufügt, aber mir sind momentan keine konkreten Vorschläge in diesem Bereich bekannt.

    
Quuxplusone 20.01.2016 23:57
quelle