33

Pay attention carefully because this is a hell of a question ;-)

I want to use template functions for generic collection actions (like search, foreach, etc.) in C while maintaining compiler static type checking. It is fairly straightforward while you're using simple callbacks like in this example:

#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]);\
  }\
}

so you can do things like:

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);
}

If I'd like to implement callbacks with return types, for example to make a "map" function, I could do:

#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 far, so good. The problem comes now, when I want my callback functions to accept any number of typed arguments.

The idea is something like:

#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*/);\
  }\
}

so, as you can see, I could declare a map function as:

MAKE_MAP(int, float, char)

giving:

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

but I cannot figure how to implement the parameter passing with the preprocessor. Here is where I ask for your help, ideas and suggestions.

(By the way, don't tell me to use a variadic function as template and passing a va_list argument to the callback, because all this stuff was because of the type checking :-p)

4
  • 19
    MAYBE IF I JUST PUSH A LITTTTLE HARDER THIS SQUARE PEG WILL FIT IN MY ROUND HOLE!!!! Commented May 21, 2009 at 17:54
  • 3
    Kudos for tagging this "preprocessor-abuse". I'm thinking right now of how I would write a MAKE_PROGRAM() macro. Commented May 21, 2009 at 17:57
  • 7
    This certainly is preprocessor abuse, but isn't the oh-so-fashionable template meta-programming really just C++ template system abuse too? Sometimes the only sensible answer is to push the tool to the edge of its usability. Commented May 21, 2009 at 20:06
  • 4
    +1 for interesting preprocessor abuse. Commented May 21, 2009 at 20:06

3 Answers 3

12

If you are on Linux/BSD Unix, take a look at queue(3) and check into /usr/include/sys/queue.h - it's been done before :)

Sign up to request clarification or add additional context in comments.

Comments

1

A recent question raised quite a few shameless preprocessor abusing libraries.

Comments

1

For information, the source code of GCC 4.6 implements similar tricks for vectors. Look into its file gcc/vec.h

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.