Ich versuche, C++ 11 Funktionen verwenden, um benutzerdefinierte Stream-Manipulatoren einfacher zu erstellen. Ich kann Lambda-Funktionen als Manipulatoren verwenden, aber nicht std::function<ostream&(ostream&)>
.Std :: Funktion als benutzerdefinierte Stream-Manipulator
Hier ist der Code, eingekocht:
#include <iostream>
#include <functional>
using namespace std;
auto lambdaManip = [] (ostream& stream) -> ostream& {
stream << "Hello world" << endl;
};
function<ostream& (ostream&)> functionManip = [] (ostream& stream) -> ostream& {
stream << "Hello world" << endl;
};
int main (int argc, char** argv) {
cout << lambdaManip; // OK
cout << functionManip; // Compiler error
}
Die zweite cout
Anweisung schlägt mit dem folgenden:
g++-4 src/Solve.cpp -c -g -std=c++0x -o src/Solve.o -I/home/ekrohne/minisat
src/Solve.cpp: In function 'int main(int, char**)':
src/Solve.cpp:24:11: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream<char>&&'
/usr/lib/gcc/i686-pc-cygwin/4.5.3/include/c++/ostream:579:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = std::function<std::basic_ostream<char>&(std::basic_ostream<char>&)>]'
Warum versagt das? Ich benutze cygwin gcc 4.5.3.
Während ich frage, bin ich nicht verrückt nach std::function
überall, 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:
auto getAdditionFunctor();
auto getAdditionFunctor() {
return [] (int x, int y) { return x + y };
};
... aber offensichtlich nicht funktioniert. Gibt es eine alternative Syntax, die funktioniert? Ich kann mir nicht vorstellen, was es sein könnte, also kann ich mit std::function
stecken bleiben.
Wenn ich eine Lösung für die zweite Frage hätte, dann wäre die erste Frage strittig.
Vielen Dank.
Definieren 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 die einfache lambda
, die ich gebaut habe, wahrscheinlich nur in eine einfache alte Funktion kompiliert, genau wie mir gesagt wurde. In der Tat, wenn ich Variable Capture verwenden, um sicherzustellen, dass lambda
keine einfache Funktion ist, schlägt der Compiler fehl. Auch Objekte mit operator()
definiert sind nicht (standardmäßig) als Manipulatoren behandelt:
class Manipulator {
ostream& operator()(ostream& stream) const {
return stream << "Hello world" << endl;
};
} classManip;
function<ostream& (ostream&)> functionManip = [] (ostream& stream) -> ostream& {
return stream << "Hello world" << endl;
};
int main (int argc, char** argv) {
const string str = "Hello world";
auto lambdaManip = [&] (ostream& stream) -> ostream& {
return stream << str << endl;
};
cout << classManip; // Compiler error
cout << lambdaManip; // Compiler error
cout << functionManip; // Compiler error
}
Weitere Update: es stellt sich heraus eine etwas robustere Lösung als die unten diejenigen mit erreicht werden:
// Tell ostreams to interpret std::function as a
// manipulator, wherever it sees one.
inline ostream& operator<<(
ostream& stream,
const function<ostream& (ostream&)>& manipulator) {
return manipulator(stream);
}
Dieser Code hat eine zusätzliche const
. Ich habe dies entdeckt und versucht, die Lösung in meinem Projekt zu implementieren.
Wollten Sie in diesen Manipulatoren eine "Rückkehr" weglassen? –
Ich hatte gelesen, dass diese impliziert sind, und das Hinzufügen von ihnen hilft nicht. In diesem Fall denke ich, dass sie mit den Rückgaben besser lesbar sind, aber ohne sie sind sie legal. Schließlich funktioniert alles gut, wenn ich 'cout << functionManip; 'ausdepretiere. –
@EdKrohne: 'return' ist ** nicht ** optional hier - Ihre Lambdas rufen UB auf, indem sie einen nicht-leeren" return type "haben und nicht wie bei jeder anderen Funktion einen Wert zurückgeben. §6.6.3/2: "* Das Ende einer Funktion ist gleichbedeutend mit einem' return' ohne Wert; dies führt zu undefiniertem Verhalten in einer Wert-zurückkehrenden Funktion. * "Scheinbar gut zu funktionieren ist nur eine mögliche Manifestation von UB. – ildjarn