Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » verschachteln von function pointers

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
15.05.2009, 18:16 Uhr
ulfenstein



Hallo,

ich habe folgende, relativ simple mathematische Aufgabe, weiß aber nicht wie es elegant in C++ zu implementieren:

ich habe eine skalare Funktion von zwei Variablen f2(x1,x2) und ein Funktional, das eine Funktion von einer Variablen auf ein Skalar abbildet, d.h. G(f1(x)) -> Zahl (der resultierende Wert von G hängt nur von f und nicht von x ab).

Als Funktion ist G deshalb vom Typ

C++:
double G(double (*fct_ptr)(double))
{
...
}



und f2

C++:
double f2(double x, double y)
{
...
}



Nun möchte ich innerhalb einer anderen Funktion, an einer Stelle mit festem x2 (x2 läuft eigentlich über eine Schleife)

C++:
G(f2(x1,x2))


aufrufen, wobei x1 von keiner Bedeutung ist (x2 aber einen festen Wert hat).
Ich brauche also einen function pointer vom Typ

C++:
double (*fct_ptr)(double x1)


, der auf f2(x1, x2) mit festem x2 zeigt.
Bin gerade etwas ratlos ob das überhaupt geht. Notfalls kann ich natürlich auch G abändern, wäre aber weniger elegant .

Dankbar für jeden Vorschlagen,
Ulfenstein
[edit 0xdeadbeef]
cpp-Tags eingefügt. Nächstes mal selbst machen.
[/cpp]

Dieser Post wurde am 16.05.2009 um 06:09 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
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.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: