Sto cercando di utilizzare le funzionalità di C++ 11 per rendere più semplice la creazione di manipolatori di flusso personalizzati. Posso usare le funzioni lambda come manipolatori, ma non std::function<ostream&(ostream&)>
.std :: funziona come un manipolatore di flusso personalizzato
Ecco il codice, si riduceva:
#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
}
Il secondo cout
dichiarazione riesce con il seguente:
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>&)>]'
Perché questo fallire? Sto usando cygwin gcc 4.5.3.
Mentre sto chiedendo, non sono pazzo di usare std::function
ovunque, a causa dei problemi di efficienza. Ma desidero scrivere funzioni che restituiscano funzioni lambda e non ho idea di come farlo senza std::function
. Ad esempio, qualcosa di simile al seguente sarebbe fantastico
auto getAdditionFunctor();
auto getAdditionFunctor() {
return [] (int x, int y) { return x + y };
};
... ma ovviamente non funziona. C'è una sintassi alternativa che funziona? Non riesco a immaginare cosa potrebbe essere, quindi potrei essere bloccato con std::function
.
Se avessi una soluzione alla seconda domanda, allora la prima domanda sarebbe discutibile.
Grazie.
Definire operator<<(ostream&, std::function<ostream&(ostream&)>
aiutato. Avevo letto erroneamente una pagina Web e avevo l'impressione che lo ostream
fosse abbastanza intelligente da trattare un oggetto arbitrario con un operator()
come manipolatore. Ho sbagliato su questo. Inoltre, il semplice lambda
che ho costruito probabilmente si stava solo compilando in una semplice vecchia funzione, proprio come mi era stato detto. Infatti, se utilizzo la cattura variabile per garantire che lo lambda
non sia una funzione semplice, il compilatore fallisce. Inoltre, gli oggetti con operator()
definiti (per default) trattati come manipolatori sono:
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
}
Ulteriore aggiornamento: si scopre una soluzione leggermente più robusti di quelli indicati può essere realizzato con:
// 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);
}
Questo codice ha un extra const
. Ho scoperto questo cercando di implementare effettivamente la soluzione nel mio progetto.
Intendevi lasciare un "ritorno" in quei manipolatori? –
Avevo letto che quelli sono impliciti e aggiungerli non aiuta. In questo caso penso che siano più leggibili con i ritorni, ma sono legali senza. Dopotutto, tutto funziona perfettamente se commento "cout << functionManip;". –
@EdKrohne: 'return' è ** not ** opzionale qui - i tuoi lambdas invocano UB avendo un tipo di ritorno non -'void' e non restituiscono un valore, proprio come con qualsiasi altra funzione. §6.6.3/2: "* Scorrere alla fine di una funzione equivale a un' return' senza valore, il che comporta un comportamento indefinito in una funzione di ritorno del valore. * "Apparire per funzionare correttamente è solo una possibile manifestazione di UB. – ildjarn