Я думаю, что то, что вы хотите сделать, может быть достигнуто с помощью страшных «X макросов». Создайте список, например
#define SUPPORTED_TYPES(X) \
X(int, "%d") \
X(float, "%f") \
, где int
- это тип, и в этом случае я использовал спецификатор формата printf в качестве другого элемента. Это может быть все, что считается действительными токенами препроцессора.
Затем вы можете генерировать все функции с помощью вредоносного макроса, например:
#define DEFINE_F(type, fmt) \
void f_##type (type param) \
{ printf(fmt "\n", param); }
SUPPORTED_TYPES(DEFINE_F)
Это создает такие функции, как void f_int (int param) { printf("%d\n", param); }
. Это очень похоже на шаблоны C ++ - функции, выполняющие одно и то же, но с разными типами.
Затем вы можете написать свой макрос _Generi c следующим образом:
void dummy (void* param){}
#define GENERIC_LIST(type, fmt) type: f_##type,
#define func(x) _Generic((x), SUPPORTED_TYPES(GENERIC_LIST) default: dummy)(x)
Здесь вы определяете общий c ASO c. список с GENERIC_LIST
, используя элемент type
, но игнорируя все остальное. Таким образом, он расширяется, например, до int: f_int,
.
. Проблема в том, что это старая проблема с «запятой», мы не можем написать _Generi c, как _Generic((x), int: f_int,)(x)
запятую после f_int
, которая запутается до синтаксиса. Я решил это с помощью предложения default
, вызывающего фиктивную функцию, не идеально ... возможно, захотите вставить assert
в эту функцию.
Полный пример:
#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);
}
Вывод :
1
2.000000
Это 100% ISO C, без расширений.