Funktionsobjekte: gleich zwei blöde Fragen
-
Hi,
habe mir gerade ein Beispiel zu Funktoren in Zusammenhang mit der STL angeschaut und habe gleich zwei blöde Fragen dazu. Hier zunächst der Beispielcode:
#include <iostream> #include <functional> #include "conio.h" struct ungerade : public unary_function<int, bool> { bool operator()(int x) const { return (x%2) != 0; } }; int main() { int i; std::cout << "int eingeben: "; std::cin >> i; if(ungerade()(i)) // (*) std::cout << i << " ist ungerade"; if(not1(ungerade())(i)) std::cout << i << " ist gerade"; _getch(); return 0; }Jetzt die Fragen:
1. In Zeile (*) kann ich mich nicht ganz mit der doppelten Klammer nach "ungerade" anfreunden. Ist "ungerade()" ein Konstruktoraufruf, um anschließend mittels des temporären "ungerade-Objekts" zu testen, ob i ungerade ist?2. Sowohl für die Basisklasse von ungerade, unary_function, als auch die Methode not1 wird laut MSDN-library der header <functional> benötigt. Wenn ich den wie oben geschehen per include einfüge, will der Compiler trotzdem nichts von unary_function und not1 wissen. Was mache ich hier falsch?
Danke vorab,
Nanuq
-
Nanuq schrieb:
1. In Zeile (*) kann ich mich nicht ganz mit der doppelten Klammer nach "ungerade" anfreunden. Ist "ungerade()" ein Konstruktoraufruf, um anschließend mittels des temporären "ungerade-Objekts" zu testen, ob i ungerade ist?
Ja. Normalerweise macht man für sowas aber auch keine Funktoren, eher wenn die Funktion dahinter "stateful" ist, also im Funktor Informationen gespeichert sind die beim nächsten Aufruf benötigt werden.
2. Sowohl für die Basisklasse von ungerade, unary_function, als auch die Methode not1 wird laut MSDN-library der header <functional> benötigt. Wenn ich den wie oben geschehen per include einfüge, will der Compiler trotzdem nichts von unary_function und not1 wissen. Was mache ich hier falsch?
Sowohl unary_function als auch not1 befinden sich genau wie cout und cin im Namespace std.
-
Danke für die schnelle Antwort!
Dann war ja eigentlich doch nur eine der beiden Fragen doof, die dafür aber ganz besonders:
LordJaxom schrieb:
Sowohl unary_function als auch not1 befinden sich genau wie cout und cin im Namespace std.

-
LordJaxom schrieb:
Nanuq schrieb:
1. In Zeile (*) kann ich mich nicht ganz mit der doppelten Klammer nach "ungerade" anfreunden. Ist "ungerade()" ein Konstruktoraufruf, um anschließend mittels des temporären "ungerade-Objekts" zu testen, ob i ungerade ist?
Ja. Normalerweise macht man für sowas aber auch keine Funktoren, eher wenn die Funktion dahinter "stateful" ist, also im Funktor Informationen gespeichert sind die beim nächsten Aufruf benötigt werden.
Naja, als Template Parameter braucht man öfters Funktoren. Ganz egal ob man im Funktor nun State braucht oder nicht.
-
hustbaer schrieb:
Naja, als Template Parameter braucht man öfters Funktoren. Ganz egal ob man im Funktor nun State braucht oder nicht.
Wie meinst Du das? Geht doch auch mit Funktionen:
#include <iostream> using namespace std; template <typename F> struct caller_t { caller_t(F f) { f(); } }; template <typename F> void call(F f) { caller_t<F> c(f); } struct functor_t { void operator ()() { cout << "functor_t" << endl; } }; void functor() { cout << "functor" << endl; } int main() { call(functor_t()); call(functor); }
-
Nachdem ihr hier eifrig diskutiert, klinke ich mich vielleicht doch noch einmal ein.
Kann man sagen, dass Funktoren Funktionszeiger ersetzen (können/sollten) und zusätzlich den Vorteil haben, dass sie als Objekte z.B. Daten speichern können?
Und kann man außerdem sagen, dass Funktoren hauptsächlich im Zusammenhang mit solchen Callback-Mechanismen (etwas wie im Beispiel von Konrad Rudolph nennt man doch so, oder?) eingesetzt werden?
Ich denke, dass ich inzwischen die Theorie verstanden habe, allerdings sehe ich - abgesehen von Callback-Funktionen - die praktischen Einsatzmöglichkeiten noch nicht wirklich. Vielleicht kann mir ja auch jemand sagen, wo man über den praktischen Einsatz etwas nachlesen kann.
-
Ein Vorteil von Funktoren ist, daß sie ein eigenständiger Typ sind. Das heißt, du kannst sie z.B. als Parameter an Template-Klassen übergeben (z.B. std::set<> und Kollegen erwarten einen Funktor als zweiten bzw. dritten Parameter).
(ja, man könnte auch eineset<double,bool(*)(double,double)>definieren, aber mit Funktoren kannst du hier wesentlich eleganter umgehen)Ein anderer Vorteil ist, daß sie interne Daten speichern können, z.B.:
struct mittelwert : public unary_function<double,void> { mittelwert() : sum(0),count(0) {} //Funktions-Operator void operator()(double val) { sum+=val; ++count; } //Ausgabe des Ergebnisses operator double() {return sum/count;} private: double sum; size_t count; }; ... vector<double> data; ... mittelwert mw=for_each(data.begin(),data.end(),mittelwert()); cout<<"Der Mittelwert ist "<<mv<<endl;