问题
I have a template like this:
template.h
----------
// Declare a function "func_type()"
void JOIN(func_, T)(T t) { return; }
#undef T
which I use like this in order to generate the same function for different types:
example.c
---------
#define T int
#include "template.h"
#define T float
#include "template.h"
I would like to have a single func
that I can use instead of funct_int
, func_float
, etc. My problem with _Generic
is that it doesn't seem possible to define the association-list dynamically. In practical terms I'd like to have something like this:
#define func(TYPE) _Generic((TYPE), AUTO_GENERATED_LIST)
instead of manually defining every new type like this:
#define func(TYPE) _Generic((TYPE), int: func_int..., float: func_float...)
Here's an example of code that is not working: https://ideone.com/HN7sst
回答1:
I think what you want to do can be achieved with the dreaded "X macros". Create a list such as
#define SUPPORTED_TYPES(X) \
X(int, "%d") \
X(float, "%f") \
where int
is the type and in this case I used printf format specifier as another item. These can be anything that counts as valid pre-processor tokens.
Then you can generate all functions through an evil macro like this:
#define DEFINE_F(type, fmt) \
void f_##type (type param) \
{ printf(fmt "\n", param); }
SUPPORTED_TYPES(DEFINE_F)
This creates functions such as void f_int (int param) { printf("%d\n", param); }
. That is, very similar to C++ templates - functions doing the same thing but with different types.
You can then write your _Generic macro like this:
void dummy (void* param){}
#define GENERIC_LIST(type, fmt) type: f_##type,
#define func(x) _Generic((x), SUPPORTED_TYPES(GENERIC_LIST) default: dummy)(x)
Here you define the generic asoc. list with GENERIC_LIST
, using the type
item but ignoring everything else. So it expands to for example int: f_int,
.
A problem with this is the old "trailing comma" problem, we can't write _Generic like _Generic((x), int: f_int,)(x)
the comma after f_int
would mess up the syntax. I solved this with a default
clause calling a dummy function, not ideal... might want to stick an assert
inside that function.
Full example:
#include <stdio.h>
#define SUPPORTED_TYPES(X) \
X(int, "%d") \
X(float, "%f") \
#define DEFINE_F(type, fmt) \
void f_##type (type param) \
{ printf(fmt "\n", param); }
SUPPORTED_TYPES(DEFINE_F)
void dummy (void* param){}
#define GENERIC_LIST(type, fmt) type: f_##type,
#define func(x) _Generic((x), SUPPORTED_TYPES(GENERIC_LIST) default: dummy)(x)
int main (void)
{
int a = 1;
float b = 2.0f;
func(a);
func(b);
}
Output:
1
2.000000
This is 100% ISO C, no extensions.
来源:https://stackoverflow.com/questions/60453659/is-it-possible-to-define-generics-association-list-dynamically