Is it possible to define _Generic's association-list dynamically?

被刻印的时光 ゝ 提交于 2020-05-13 18:48:23

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!