C Funktionspointer auf sich selbst

Gast #2584437
Hallo,

ich möchte eine Funktion erstellen, die einen Zeiger auf eine Funktion 
mit gleicher Signatur wie die Funktion selbst zurückgibt. Also so, dass 
man die Funktion mittels

f(bla)(blub)(foo)...

beliebig oft direkt nacheinander aufrufen kann. Ist das in C(++) möglich 
und wenn ja, wie hat der Funktionskopf auszusehen?

- jgdo -
#2584484
Vielleicht mit einem Funktionsobjekt:
1
#include <iostream>
2

3
class MyFO
4
{
5
public:
6
    MyFO &operator()( int a )
7
    {
8
        std::cout << "operator()( int a = " << a << " )" << std::endl;
9
        return *this;
10
    }
11
};
12

13
int main( int nargs, char **args )
14
{
15
    MyFO     myFO;
16

17
    myFO( 5 )( 4 )( 42 );
18
}

Das ergibt:
1
F:\kw>cl /EHsc t.cpp
2
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
3
Copyright (C) Microsoft Corporation.  All rights reserved.
4

5
t.cpp
6
Microsoft (R) Incremental Linker Version 9.00.30729.01
7
Copyright (C) Microsoft Corporation.  All rights reserved.
8

9
/out:t.exe
10
t.obj
11

12
F:\kw>t
13
operator()( int a = 5 )
14
operator()( int a = 4 )
15
operator()( int a = 42 )

Von wegen parse error ... :-)
#2584499
Sein Problem ist in C in der Tat nicht trivial bzw. vielleicht gar nicht 
lösbar, weil man den Typ "Zeiger auf eine Funktion..." in derselben 
Typdefinition noch nicht als Rückgabe der Funktion verwenden kann.

Wie will man dann eine Funktion definieren, die einen Zeiger auf sich 
selbst liefert? So eine leere forward-Deklaration wie bei structs gibt 
es für Funktionen ja nicht.
Gast #2584508
Danke für die Antworten Leute.

@Karl Heinz Buchegger
Das ist eine Möglichkeit, aber ich wollte die Casts eben vermeiden. 
Schade dass es direkt nicht geht.

@Klaus Wachtler
Ist eine Klasse und keine Funktion.

@alle
mir gings eher um das Prinzip, eine echte Anwendung dafür habe ich 
nicht. Ich habe nur eine Funktion, die mehrmals nacheinander mit 
verschiedenen Parametern aufgerufen wird und ich wollte mal einfach 
etwas Tipparbeit sparen ;)
(Firma: Basta) #2584529
int res;

void *Func(int p1) {
  res += p1;
  return &Func;
}

int main(void) {
  res = 0;

  int (*p)(int) = Func(5);
  (*p)(10);

  printf("res=%d", res);
}


Also irgendwie krieg ich das Func(x)(y) nicht hin. Weiß jemand anderes 
weiter?
#2584626
Kan asta schrieb:
> int res;
>
> void *Func(int p1) {
>   res += p1;
>   return &Func;
> }

Du hast die Problemstellung noch nicht verstanden

> Also irgendwie krieg ich das Func(x)(y) nicht hin. Weiß jemand anderes
> weiter?

Sieh dir den FAQ Link von weiter oben an. Da sind 2 Lösungsmöglichkeiten 
gegeben. Beide nicht besonders schön.
Das Problem, wie schon weiter oben vermerkt, besteht darin, dass es 
sowas wie eine 'Forward-Deklaration' für Funktionspointer nicht gibt. 
Die würde man aber brauchen, damit man einen Funktionspointer machen 
kann, auf eine Funktion die genau diesen Funktionspointer-Typ liefert.
#2584644
  jgdo schrieb:
> @Klaus Wachtler
> Ist eine Klasse und keine Funktion.

Manchen kann man es nie recht machen...

Dann halt als Funktion:
1
#include <iostream>
2

3
class MyFO
4
{
5
private:
6
    MyFO (*m_f)( int a );
7

8
public:
9
    MyFO( MyFO (*f)( int a ) )
10
        : m_f(f)
11
    {}
12

13
    MyFO operator()( int a )
14
    {
15
        return m_f( a );
16
    }
17
};
18

19
MyFO f( int a )
20
{
21
    std::cout << "operator()( int a = " << a << " )" << std::endl;
22
    return MyFO( f );
23
}
24

25
int main( int nargs, char **args )
26
{
27
    f( 5 )( 4 )( 42 );
28
}

Gleiche Ausgabe wie oben.
Gast #2584669
Hm, was spricht dagegen die Parameter in ein Array zu packen und über 
dieses zu Iterieren? Ob es nun besser ist, das Array als ganzes an die 
Funktion zu übergeben oder jeden Parameter einzeln ist dann wieder ein 
anderes Thema. (ersteres ist besser lesbar und sollte auch in 
schnellerem Code resultieren, letzteres ist universeller)
#2584738
max schrieb:
> Hm, was spricht dagegen die Parameter in ein Array zu packen und über
> dieses zu Iterieren?


Na, ja. Das ganze war ja bis jetzt nur eine Spielerei :-)

so richtig geil wird das ganze dann, wenn eine Funktion (abhängig vom 
Parameter) nicht sich selbst zurückgibt, sondern einen Pointer auf eine 
ganz andere Funktion. Man kann da dann ein ganzes Netzwerk von 
Funktionsaufrufen hinter der harmlos anmutenden Syntax

   foo(4)(5)(6)(8);

(oder auch

    do {
      f = f(Werte[i++]);
    } while( f );
)

aufbauen, das kein Mensch mehr ohne 5 Liter Kaffee und eine Großpackung 
Baldrian durchschaut :-) Sowas nennt man dann "aktive 
Arbeitsplatzsicherung".
Gast #2585427
So gehts:
1
#include "stdio.h"
2

3
typedef int (*fp)(int);
4

5
fp f(int i)
6
{
7
  printf("i=%i\n", i);
8
  return (fp)f;
9
}
10

11
int main(int argc, char ** argv)
12
{
13
  f(1)(2);
14
  return 1;
15
}

aber leider nur mit zweifachem Aufruf. Beim dreifachen Aufruf
1
f(1)(2)(3);
meint der gcc error: called object ‘f(1)(2)’ is not a function
#2585469
kann man nicht einfach mit einem Makro einen Zeiger auf ein Array von 
Parametern übergeben und dann die Funktion einfach mehrmals aufrufen?

sowas wie
1
#define foo(var) foo_fctn({ (var) })
2

3
//oder falls das nicht geht:
4

5
#define foo(var)                \
6
int array[]={ (var) , 0x7FFF }; \
7
foo_fctn(array);
8

9
int foo_fctn(int * array)
10
{
11
    int i=0;
12
    while( array[i] != 0x7FFF )
13
    {
14
       res += foo_nocheine( array[i] );
15
       i++;
16
    }
17
    return res;
18
}
19

20
var = foo(1);
21
var = foo(1,2);
22
var = foo(1,2,3);
23
var = foo(1,2,3,4);

(alles nicht getesten, hab auf meinem Laptop keine IDE ^^)

EDIT: nagut, das array wird bei mehrfacher Verwendung des Makros im 
selben Gültigkeitsbereich Probleme machen aber das Prinzip sollte ja 
ersichtlich sein oder?

EDIT2: werden die Kommas Probleme machen? vielleicht Klammern 
"Übergeben" und temporär Klammern als Komma definieren? xD (falls die 
erste Variante nicht funktioniert)
Persönliche Seite #2586078
Karl Heinz Buchegger schrieb:
> so richtig geil wird das ganze dann, wenn eine Funktion (abhängig vom
> Parameter) nicht sich selbst zurückgibt, sondern einen Pointer auf eine
> ganz andere Funktion [..] das kein Mensch mehr ohne 5 Liter Kaffee und
> eine Großpackung Baldrian durchschaut :-)
> Sowas nennt man dann "aktive Arbeitsplatzsicherung"
Oder Method Chaining/Fluent Interface:
http://en.wikipedia.org/wiki/Method_chaining
http://en.wikipedia.org/wiki/Fluent_interface
Ich nutze das ab und an mal konnte mich aber bisher noch nicht im großen 
Stil dafür erwärmen...

Wird zwar immer im Zusammenhang mit OO genannt, aber wieso sollte man 
das nicht auch mal in C umsetzen? Der arme Compiler...
#2586294
Klaus Wachtler schrieb:
> Wieso?
> Das ist nur eine andere Form eines Zustandsautomats - für den wird man
> auch nicht automatisch abgemahnt.

Normalerweise sollte es in einer Firma Richtlinien für die Codierung 
geben. Wenn die Firma Wert auf Qualität legt (das tut freilich nicht 
jede), dann sorgt sie auch dafür, dass diese Richtlinien eingehalten 
werden. Solche Tools wie z.B. MISRA C++ Code Checker mögen in der Regel 
"arbeitsplatzsichernden Code" nicht besonders :-)
Moderator #2586301
jgdo schrieb:
> ich möchte eine Funktion erstellen, die einen Zeiger auf eine Funktion
> mit gleicher Signatur wie die Funktion selbst zurückgibt.

In Sprachen mit dynamischer Typisierung (z.B. Python) ist das kein
Problem:
1
def f(x):
2
  print('f called with', x)
3
  return f
4

5
f(1)(2)(3)(4)

liefert
1
f called with 1
2
f called with 2
3
f called with 3
4
f called with 4

Viele Sprachen mit statischer Typisierung scheinen aber Probleme zu
haben, den Typ dieser Funktion compiler-intern darzustellen. Auch in
Haskell, wo man das Ausdenken der Funktionssignaturen i.Allg. dem
Compiler überlassen und ganz lapidar
1
f x = f

schreiben kann, meckert der Compiler:
1
    Occurs check: cannot construct the infinite type: t1 = t0 -> t1
2
    In the expression: f
3
    In an equation for `f': f x = f

Das ist dort aber kein großes Problem, da dieses Konstrukt sowieso nur
für seiteneffektbehaftete Funktionen von Nutzen ist, die es in Haskell
gar nicht gibt.

Läubi .. schrieb:
> Oder Method Chaining/Fluent Interface:

Auch ganz interessant in diesem Zusammenhang:

  http://en.wikipedia.org/wiki/Continuation-passing_style

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 14 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.