Funktionale Programmierung in C mit Makro-“Higher Order Function”-Generatoren

Lesezeit: 3 Minuten

Benutzer-Avatar
Fortran

Pass gut auf, denn das ist eine höllische Frage 😉

Ich möchte Vorlagenfunktionen für generische Sammlungsaktionen (wie Suche, Foreach usw.) in C verwenden und gleichzeitig die statische Typüberprüfung des Compilers beibehalten. Es ist ziemlich einfach, wenn Sie einfache Rückrufe wie in diesem Beispiel verwenden:

#define MAKE_FOREACH(TYPE)\
void foreach_##TYPE (TYPE[n] array, int n, void(*f)(TYPE)) {\
  for(int i = 0; i < n; i++) {\
    f(array[i]);\
  }\
}

damit du Dinge tun kannst wie:

MAKE_FOREACH(int)
MAKE_FOREACH(float)

void intcallback(int x){
  printf("got %d\n", x);
}

void floatcallback(float x){
  printf("got %f\n", x);
}

int main(){
  int[5] iarray = {1,2,3,4,5};
  float[5] farray = {1.0,2.0,3.0,4.0,5.0};
  foreach_int(iarray, 5, intcallback);
  foreach_float(farray, 5, floatcallback);
}

Wenn ich Callbacks mit Rückgabetypen implementieren möchte, um beispielsweise eine “Map” -Funktion zu erstellen, könnte ich Folgendes tun:

#define MAKE_MAP(TYPE, RTYPE)\
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE)) {\
  RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\
  for(int i = 0; i < n; i++) {\
    result[i]=f(array[i]);\
  }\
}

So weit, ist es gut. Das Problem kommt jetzt, wenn ich möchte, dass meine Callback-Funktionen eine beliebige Anzahl von typisierten Argumenten akzeptieren.

Die Idee ist so etwas wie:

#define MAKE_MAP(TYPE, RTYPE, ...)\
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE, __VA_ARGS__), __VA_ARGS__)
/*this would work for the declaration (because just the types would be enough)
but the  parameter names are missing :-s*/ \
{\
  RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\
  for(int i = 0; i < n; i++) {\
    result[i]=f(array[i], /*here the names of the parameters, in order*/);\
  }\
}

Also, wie Sie sehen können, könnte ich erklären eine Kartenfunktion als:

MAKE_MAP(int, float, char)

geben:

float* map_int(int[n] array, int n, float(*f)(int, char), char);

aber ich kann nicht herausfinden, wie implementieren die Parameterübergabe mit dem Präprozessor. Hier bitte ich um Ihre Hilfe, Ideen und Anregungen.

(Übrigens sagen Sie mir nicht, dass ich eine Variadic-Funktion als Vorlage verwenden und ein va_list-Argument an den Callback übergeben soll, weil all dieses Zeug wegen der Typprüfung war :-p)

  • VIELLEICHT, WENN ICH NUR EIN WENIG HÄRTER DRÜCKE, PASST DIESER QUADRATISCHE PEG IN MEIN RUNDES LOCH!!!!

    – mqp

    21. Mai 2009 um 17:54 Uhr

  • Kudos für das Markieren dieses “Präprozessor-Missbrauchs”. Ich denke gerade darüber nach, wie ich ein MAKE_PROGRAM() Makro schreiben würde.

    – Eric Petroelje

    21. Mai 2009 um 17:57 Uhr

  • Dies sicherlich ist Präprozessor-Missbrauch, aber ist die ach so modische Template-Meta-Programmierung nicht auch nur C++-Template-System-Missbrauch? Manchmal die einzig vernünftige Antwort ist um das Werkzeug an den Rand seiner Verwendbarkeit zu bringen.

    – RBerteig

    21. Mai 2009 um 20:06 Uhr

  • +1 für interessanten Präprozessormissbrauch.

    – RBerteig

    21. Mai 2009 um 20:06 Uhr

Wenn Sie Linux/BSD Unix verwenden, werfen Sie einen Blick auf Warteschlange(3) und einchecken /usr/include/sys/queue.h – es wurde schon einmal gemacht 🙂

Benutzer-Avatar
diapir

Eine aktuelle Frage hat einige schamlose Präprozessor-Missbrauchsbibliotheken aufgeworfen.

Zur Information, der Quellcode von GCC 4.6 implementiert ähnliche Tricks für Vektoren. Schauen Sie in seine Datei gcc/vec.h

1381980cookie-checkFunktionale Programmierung in C mit Makro-“Higher Order Function”-Generatoren

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy