Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

15.02.2009, 01:08

Funktionszeiger vs. template + operator()

Hi,
also wenn ich eine Funktion habe, die irgendwas miteiner anderen machen soll und man daher eine Funktion per Parameter übergeben will, wie sollte man das am besten machen?

Ich habe jetzt mal eine Lösung mit operator() überladen und dann der Hauptfunktion ein Templateobjekt übergeben, wobei dieses Objekt dann wie eine Funktion benutzt wird.
Es gibt ja nun auch Funktionszeiger mit denen ich aber noch so gut wie gar nicht gearbeitet habe.

Das sind jetzt mindestens 2 Techniken, die das selbe erzielen. Die Frage ist, was ist besser? Wo liegen vor und nachteile?
Bei der Template Methode muss man eine Klasse mit () operaotr schreiben, was komisch aussieht. Aber dafür geschieht alles zur Kompilierzeit und mit Zeigern könnte es theoretisch Laufzeitprobleme geben?

Also,was soll ich bevorzugen und gibt es vielleicht noch andere, bessere Methoden?

[edit] Ein Funktionstemplate Beispiel: http://rafb.net/p/bfdb3X40.html [/edit]
Lieber dumm fragen, als dumm bleiben!

the[V]oid

Alter Hase

Beiträge: 775

Wohnort: Aachen

  • Private Nachricht senden

2

15.02.2009, 01:36

Ein Template-Objekt? Was ist denn das nun? Ich kenn nur Template-Funktionen und Template-Klassen. Hab jetzt mal vermutet, dass du das letztere meinst, da ich mir auf Template-Funktionen in dem Zusammenhang irgendwie keinen Reim machen konnte. In dem Quelltext verwendest du nun aber eine Template-Funktion. Ich blick grade nicht durch ^^

Aber um mal auf das Thema einzugehen: Ich denke, die Klassen-Variante ist zwar aufwendiger, dafür ist sie aber objektorientiert, was ein großer Vorteil ist, da man so die Vorzüge der Polymorphie genießen kann. Allerdings würde ich es dann ohne Templates machen: Einfach (jetzt vereinfacht gesagt) eine abstrakte Oberklasse "Funktion", von der dann die Funktionsklassen abgeleitet werden. Ich finde Templates sind nicht schön, manchmal sicher praktisch, aber wenn man sie vermeiden kann, sollte man es auch tun. Dann spart man sich auf jeden Fall schonmal eine Menge ärger, wenn man sie in Bibliotheken verwendet.
<< an dieser Stelle ist eine Signatur verstorben >>

3

15.02.2009, 01:45

Mir ist aufgefallen dass ich in der Objekten auch quasi Standardparameter speichern kann, was mit Funktionszeiger denke ich nicht möglich sein dürfte.

Die Idee von dir, Polymorphie statt Templates zu benutzen sollte man sich auch überlegen. Bei Templates hätte man wohl die Funktion mehrfach im Speicher, bei Polymorphie wäre aber der Funktionsaufruf minimal langsamer da er zur Laufzeit auf die vtable zugreifen müsste und man hätte diese Basisklasse, die man sich bei Templates sparen kann. Allerdings sind das alles keine richtig schwerwiegende Argumente, also gibt es noch bessere für eins von beiden?
Lieber dumm fragen, als dumm bleiben!

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

4

15.02.2009, 09:36

Zitat von »"Jonathan_Klein"«

Mir ist aufgefallen dass ich in der Objekten auch quasi Standardparameter speichern kann, was mit Funktionszeiger denke ich nicht möglich sein dürfte.


Jap, das stimmt.


Anyway, der von dir verwendete Ansatz funktioniert doch eh mit beidem:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using namespace std;
 
class Funktion1
{
    public:
    int operator() (int x, int y)
    {
        return x+y;
    };
};
 
class Funktion2
{
    public:
    int operator() (int x, int y)
    {
        return x-y;
    };
};

int Funktion3(int x, int y)
{
  return x * y;
}
 
template<typename Funktion> void DoSomething(Funktion F)
{
    cout << F(17, 4);
}
 
int main()
{
    DoSomething(Funktion1());
    DoSomething(Funktion2());
    DoSomething(Funktion3);
};

5

15.02.2009, 10:39

Templates sind eigentlich nicht dazu gedacht, vor allem weil hier die Funktionen alle die selbe Signatur und den selben Rückgabetypen haben. Man kann hier nämlich alle Funktionen oder Funktionsobjekte mit zwei arithmetischen Parametern übergeben, bei denen der Rückgabetyp einer Überladung von std::ostream::operator<< entspricht oder implizit zu einer solchen konvertierbar ist.

Vor allem wenn du die Flexibilität eines Funktors nicht brauchst, würde ich eher zu Funktionszeiger raten. Eine gute Einführung dazu findest du hier.

C-/C++-Quelltext

1
2
3
4
5
6
typedef int (*IntFunction)(int, int);

void DoSomething(IntFunction F)
{
    cout << F(17, 4);
}

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

6

15.02.2009, 10:43

Zitat von »"Nexus"«

Templates sind eigentlich nicht dazu gedacht, vor allem weil hier die Funktionen alle die selbe Signatur und den selben Rückgabetypen haben.


Warum nicht dazu gedacht? Die STL is voll davon...

Zitat von »"Nexus"«

Man kann hier nämlich alle Funktionen oder Funktionsobjekte mit zwei arithmetischen Parametern übergeben, bei denen der Rückgabetyp einer Überladung von std::ostream::operator<< entspricht oder implizit zu einer solchen konvertierbar ist.


Naja, das ist jetzt aber nicht unbedingt etwas schlechtes, oder!?

7

15.02.2009, 10:51

Zitat von »"dot"«

Warum nicht dazu gedacht? Die STL is voll davon...
Templates sind eher für Fälle konzipiert, wo unterschiedliche Typen übergeben werden - so wie in der STL. Wenn man nur Funktionen vom gleichen Typ übergeben soll, sind Funktionszeiger oder allenfalls Funktoren der bessere Weg.

Zitat von »"dot"«

Naja, das ist jetzt aber nicht unbedingt etwas schlechtes, oder!?
So wie ich die Fragestellung verstanden habe schon. Wie gesagt sollen doch Funktionen mit int als Rückgabetyp und zwei int-Parametern übergeben werden? Von etwas anderem war jedenfalls nie die Rede.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

8

15.02.2009, 11:17

Naja stellt sich die Frage wie stark man die Typen einschränken will. Auch bei der template-Variante kann man nicht jeden belieigen Typ übergeben. Der Typ ist dort aus der Verwendung heraus eingeschränkt. Natürlich kann man alle möglichen Typen verwenden die die (von dir bereits genannten) Anforderungen erfüllen, was natürlich sehr viel flexibler ist als rein ein Funktionspointer.

Welche Variante sich anbietet hängt jetzt natürlich davon ab wie stark man den Raum der möglichen Typen beschränken will. Und das ist eine Sache die wohl vom konkreten Anwendungsfall abhängt (will ich wirklich nur Funktionen die zwei ints als Parameter haben und einen int returnen zulassen, oder will ich auch Funktoren oder Delegaten oder Funktionsobjekte mit gebundenen Parametern, oder...)
Natürlich bringt das template einige dem template-Konzept inherente Konsequenzen mit sich, die man bedenken muss. Z.B. dass die Implementierung im Header stehen muss (zumindest wenn man das ganze auf einem normalsterblichen compiler kompillieren will) und natürlich auch dass evtl. redundanter Code erzeugt wird, usw...
Man könnte statt eines Funktionspointers auch ein Interface verwenden (vielleicht was in Richtung Strategy-Pattern?), eine Variante die imo auch zu überlegen wäre.

Anyway, imo kann man hier keine pauschale Aussage anhand eines einfachen Beispiels treffen, sondern muss über dieses Problem im Kontext einer konkreten Anwendung entscheiden...

9

15.02.2009, 11:28

Hm hab mal wieder nicht alles durchgelesen, aber guck dir evtl. einfach mal den Header <functional> an ;)
=> Die Methode per Template lässt einem wesentlich mehr möglichkeiten bei der Wahl der genutzten Funktion. Sonst bekommst du bei Memberfunktionen usw. schonmal leicht ein Problem ... bzw. wenn du mit Funktionszeigern arbeitest, würde ich dir immer empfehlen, einen void-Zeiger mit zu übergeben (als Parameter), damit man sich es notfalls noch inne Klasse (per this-Zeiger übergeben und static-Funktion) packen kann ;)

Achja und fast vergesse:
boost::function geht auch noch ;)
Devil Entertainment :: Your education is our inspiration
Der Spieleprogrammierer :: Community Magazin
Merlin - A Legend awakes :: You are a dedicated C++ (DirectX) programmer and you have ability to work in a team? Contact us!
Siedler II.5 RttR :: The old settlers-style is comming back!

Also known as (D)Evil

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

10

15.02.2009, 11:42

Also ich würde auch eher zu der Funktor Varianten tendieren, weil man nie wissen kann, was der Benutzer machen will und man so flexibler ist, als mit einem Funktionszeiger. Andernfall müsste man, wie Deviloper das mit den Daten mit einem void - Zeiger machen. Aber das imo einfach nur.. C..

Und das schönste ist ja, dass man ebenfalls Funktionen übergeben kann.

Werbeanzeige