001
16.05.2009, 05:48 Uhr
0xdeadbeef
Gott (Operator)
|
Die einfachste Möglichkeit, einen festen Wert einzusetzen, wäre mit einer eigenen Funktion dafür:
C++: |
double f2_fest(double x) { return f2(x, 3.141); }
|
...und die statt f2 an G zu übergeben. Da aber x2 bei dir nicht wirklich konstant ist, kommen wir damit nicht weit. Glücklicherweise gibt es in der C++-Standardbibliothek einen (wenn auch recht begrenzten) Weg, damit umzugehen: std::bind2nd in Verbindung mit std::ptr_fun. Das sieht etwa so aus:
C++: |
#include <iostream> #include <functional>
double add(double x, double y) { return x + y; }
int main() { std::cout << std::bind2nd(std::ptr_fun(add), 2.0)(3.0) << std::endl; }
|
std::ptr_fun ist eine Funktionsvorlage, die in diesem Fall ein std::binary_function-Objekt erstellt, das die Attribute bereitstellt, die std::bind2nd braucht (insbesondere erkennt es die Signatur der Funktion). Allerdings ist die Typdefinition des Funktionsobjekts derart scheußlich, dass ich bei der Benutzung ebenfalls zu Funktionsvorlagen rate - sonst sähe G etwa so aus:
C++: |
double G(std::binder2nd<std::pointer_to_binary_function<double, double, double> > const &func);
|
Das ließe sich zwar mit einem typedef beheben, aber die Funktion nähme dann immer noch keine normalen Funktionen mehr entgegen. Sinnvoller ist da:
C++: |
template<typename func_t> double G(func_t const &func) { return func(argument); }
// ...
result = G(std::bind2nd(std::ptr_fun(f2, x2));
|
Dann erwartet G nur noch, dass das Objekt einen operator() bereitstellt, der einen double als Argument akzeptiert und einen double (oder einen darin umwandelbaren Typ) entgegennimmt.
Das bind1st/bind2nd-API ist allerdings etwas hölzern, und im neuen C++-Standard wird es eine bessere Möglichkeit geben. Bis dahin gibt es eine Boost-Bibliothek, die das neue API inspiriert hat (vieles, was im neuen Standard enthalten sein wird, ist in Boost gewachsen) und das ganze hübscher kann. Das sieht etwa so aus:
C++: |
#include <iostream>
#include <boost/bind.hpp>
double add(double x, double y) { return x + y; }
int main() { std::cout << boost::bind(add, _1, 2.0)(3.0) << std::endl; }
|
bzw.
C++: |
#include <iostream>
#include <boost/bind.hpp> #include <boost/function.hpp>
double add(double x, double y) { return x + y; }
int main() { boost::function<double(double)> func = boost::bind(add, _1, 2.0); std::cout << func(3.0) << std::endl; }
|
_1 ist dabei eine Art Platzhalter für ein später übergebenes Argument, vordefiniert gibt's die bis _9 - danach musst du boost::arg<10> etc. schreiben oder eigene Platzhalter definieren. Das schöne hieran ist außerdem, dass boost::function einen Konstruktor für die übergebene Signatur zur Verfügung stellt, so dass G keine Vorlage mehr sein muss:
C++: |
#include <iostream> #include <boost/bind.hpp> #include <boost/function.hpp>
double add(double x, double y) { return x + y; } double ident(double x) { return x; }
void print(boost::function<double(double)> const &func) { std::cout << func(2.0) << std::endl; }
int main() { print(boost::bind(add, _1, _1)); print(ident); }
|
(boost::bind(add, _1, _1) liefert hier ein Funktionsobjekt zurück, dass den ersten übergebenen Parameter als ersten und zweiten an add weitergibt).
Wenn sich eine externe Bibliothek nicht völlig verbietet, empfehle ich wirklich die Boost-Option. Ansonsten sollte es sich mit bind2nd aber auch erledigen lassen.
Nachtrag:
Boost.Bind ist hier vollständig dokumentiert: www.boost.org/doc/libs/1_39_0/libs/bind/bind.html Vorkompilierte Pakete der gesamten Boost-Bibliotheken für Visual C++ gibt es hier: www.boostpro.com/download
...obwohl boost.bind speziell eine Header-Only-Bibliothek ist, du also speziell dafür die vorkompilierten Pakete gar nicht brauchst (Die Sourcen genügen). In den meisten Linux-Distributionen ist Boost schon enthalten, befrag ggf. deinen Paketmanager. -- Einfachheit ist Voraussetzung für Zuverlässigkeit. -- Edsger Wybe Dijkstra Dieser Post wurde am 16.05.2009 um 06:28 Uhr von 0xdeadbeef editiert. |