C++ Zwei Arten für Funktionszeiger?

S

Spacy

Gast
Unser Prof. hat in einer alten Klausur folgenden Code vorgegeben:
PHP:
template <typename Iterator, typename ElementType>
void fuerAlle(Iterator anfang, Iterator ende, ElementType f(ElementType)) {
    for (; anfang < ende; anfang++) {
        *anfang = f(*anfang);
    }
}

Laut meinem C++ Buch werden Funktionszeiger aber folgendermaßen verwendet:
PHP:
bool compare(double a, double b) { ... } // tatsächliche Funktion

int main() {
  bool (*funcptr)(double, double); // deklarieren
  funcptr = compare; // zuweisen
  (*funcptr)(9.1, 7.2); // aufrufen
}

Der Unterschied besteht darin, zum Deklarieren und Aufrufen den Funktionsnamen mit oder ohne vorangestelltem * zu schreiben.


Also habe ich eben mal den Code angepasst:
PHP:
template <typename Iterator, typename ElementType>
void fuerAlle(Iterator anfang, Iterator ende, ElementType (*f)(ElementType)) {
    for (; anfang < ende; anfang++) {
        *anfang = (*f)(*anfang);
    }
}

Der g++ Compiler akzeptiert beides und es funktioniert auch beides korrekt. (Siehe main.cpp im Anhang)


Was genau ist der Unterschied?
 

Anhänge

Zuletzt bearbeitet:
Das sind zwei Formen für das Gleiche. Benutzen solltest du aber beide nicht. ;-)
Das Interface sollte man so schreiben:
Code:
template <typename Iterator,  typename Function>  void fuerAlle(Iterator anfang, Iterator ende, Function f);
So klappt es sowohl mit Funktoren als auch mit Funktionen. Die Typsicherheit wird über die Iteratoren und die Funktion gewährleistet.
Code:
for (; anfang < ende; anfang++) { 
        *anfang = f(*anfang); 
    }
Das ist zwar legal, aber eigentlich gleich zweifach verwerflich. 1. Das ist ein while-Schleife und keine verkrüppelte for-schleife. Zweiten niemals die Daten ändern, wenn man etwas per pseudo copy-by-value übergibt.
EDIT Das zweite sollte ich ein bisschen anders formulieren, da sich for_each natürlich genauso verhält. Gut ist es trotzdem nicht. Man sollte einen Output-Iterator wie in bspw transform benutzen.
 
Zuletzt bearbeitet:
"Klugscheißer-Anmerkung"
in der Schleife wird mit einen "<"-Vergleich das Abbruchkriterium spezifiziert. Das führt dazu, dass die Funktion auf Iteratoren-Typen mit einer Kleiner-Relation eingeschränkt. Die allgemeinere Variante ist:
Code:
while(anfang != ende) {
   *anfang = f(*anfang);
   ++anfang;
}
 
Klugscheiß2: Die Klasse von Iteratoren mit "<" heißt "random access iterator" ;-)

Das habe ich gestern glatt überlesen, genau wie den Post-Inc, den du auch verbessert hast.
 
ghorst schrieb:
1. Das ist ein while-Schleife und keine verkrüppelte for-schleife.
Das ist eine for-Schleife - while wäre wohl eher verkrüppelt. Warum? Wegen dem zwingenden Inkrement in jedem Durchlauf. (mal davon abgesehen, dass das wohl ein wenig eine Religionsfrage ist... :)) Machst du continue, spuckt while dir in die Suppe. for bewahrt dich davor, das Inkrement zu vergessen (eben insbesondere dann, wenn der Rumpf komplexer als eine Anweisung wird). Sehr gut um sich vor sich selbst zu schützen und explizit dem Lesenden klarzustellen - pro Durchlauf 1 Inkrement.
 
Zurück
Oben