C Funktionspointer auf sich selbst

Gast #2584437
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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 ;)
#2584626
Lesenswert?

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
Lesenswert?

  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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren