Search code examples
ctypespreprocessor

How to have a function pointer type that takes an arbitrary pointer as argument?


I have a function that applies a function of type apply_fn to each element of a list, and a macro that will declare a temporary function an pass it to list_apply:

typedef void apply_fn( void * );

void list_apply( t_list *lst, apply_fn *apply );

# define list_apply( lst, apply_fn_body ) \
  do {\
    void _l_function_ apply_fn_body\
    list_apply(lst, _l_function_);\
  while (0)

I use this macro to simulate an anonymous function (like in js) so I can call my function like this for example:

list_apply(&my_list, (void * elem) {
  // do something with the element
});

So everything works fine until this point (with gcc), but I want to be able to call my function like this for example:

list_apply(&my_list, (int * elem) {
  // do something with element as an integer
});

I know that I can define my function type like this:

typedef void apply_fn();

And it works fine then but if for example I do this:

list_apply(&my_list, ( void ) {
  // function that takes no parameter instead of one pointer
});

I want it to still throw a compilation error instead of undefined behavior, what I'd like to be able to do is:

typedef void apply_fn( any_type * );

That's of course not possible but are there some alternatives that would do the same ?


Solution

  • I assume that this solution is limited only to GCC world.

    You need two nested functions. One that processes any_type* and a wrapper that maps it from void*. Finally, pass the wrapper to list_apply().

    You need something that expands this code:

    list_apply(&my_list, (int * elem) { *elem = 42; });
    

    to this:

    do {
        void _l_function_(int * elem) { *elem = 42; }
        void _l_wrapper_(void* elem) { _l_function_(elem); }
        list_apply(lst, _l_wrapper_);
    }  while (0)
    

    The possible macro could be:

    # define list_apply( lst, type, apply_fn_body )          \
      do {                                                   \
        void _l_function_ apply_fn_body                      \
        void _l_wrapper_(void* elem) { _l_function_(elem); } \
        list_apply(&lst, _l_wrapper_);                       \
      } while (0)