Skip to content

Instantly share code, notes, and snippets.

@newlawrence
Last active January 26, 2024 16:40
Show Gist options
  • Save newlawrence/865992fb10821fd6626d70bc6db818d9 to your computer and use it in GitHub Desktop.
Save newlawrence/865992fb10821fd6626d70bc6db818d9 to your computer and use it in GitHub Desktop.
A "not too much elegant" (and the only) way to get a templated, variadic and type-safe function in pure C
#include <stdio.h>
#define COUNT(...) (sizeof((int[]){ __VA_ARGS__ })/sizeof(int))
#define __eval(x0, x1, x2, x3, ...) _Generic((x0), \
void*: _Generic((x1), int: _evali, double: _evald), \
int: _evali, \
double: _evald \
)( \
COUNT(__VA_ARGS__) - _Generic((x0), void *: 1, default: 0), \
_Generic((x0), void*: (x0), default: NULL), \
_Generic((x0), void*: (x1), default: (x0)), \
_Generic((x0), void*: (x2), default: (x1)), \
_Generic((x0), void*: (x3), default: (x2)) \
)
#define eval(...) __eval(__VA_ARGS__, 0, 0, 0, 0)
void _evali(size_t c, void* e, int x, int y, int z) {
if (e) printf("called function with handler and ints: ");
else printf("called function without handler and ints: ");
switch(c) {
case 1: printf("%d\n", x); break;
case 2: printf("%d %d\n", x, y); break;
case 3: printf("%d %d %d\n", x, y, z); break;
}
}
void _evald(size_t c, void* e, double x, double y, double z) {
if (e) printf("called function with handler and doubles: ");
else printf("called function without handler and doubles: ");
switch(c) {
case 1: printf("%f\n", x); break;
case 2: printf("%f %f\n", x, y); break;
case 3: printf("%f %f %f\n", x, y, z); break;
}
}
int main(int argc, char* argv[]) {
void* handler = (void*)(&printf);
eval(1);
eval(1, 2);
eval(1, 2, 3);
eval(handler, 1);
eval(handler, 1, 2);
eval(handler, 1, 2, 3);
eval(1.);
eval(1., 2.);
eval(1., 2., 3.);
eval(handler, 1.);
eval(handler, 1., 2.);
eval(handler, 1., 2., 3.);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment