Можно ли динамически определять список ассоциаций _Generi c? - PullRequest
2 голосов
/ 28 февраля 2020

У меня есть такой шаблон:

template.h
----------
// Declare a function "func_type()"
void JOIN(func_, T)(T t) { return; }
#undef T

, который я использую таким образом, чтобы сгенерировать одну и ту же функцию для разных типов:

example.c
---------
#define T int
#include "template.h"

#define T float
#include "template.h"

Я хотел бы иметь сингл func, который я могу использовать вместо funct_int, func_float, et c. Моя проблема с _Generic заключается в том, что невозможно определить список ассоциаций динамически. В практическом плане я хотел бы иметь что-то вроде этого:

#define func(TYPE) _Generic((TYPE), AUTO_GENERATED_LIST)

вместо того, чтобы вручную определять каждый новый тип, подобный этому:

#define func(TYPE) _Generic((TYPE), int: func_int..., float: func_float...)

Вот пример кода, который не работает : https://ideone.com/HN7sst

1 Ответ

2 голосов
/ 28 февраля 2020

Я думаю, что то, что вы хотите сделать, может быть достигнуто с помощью страшных «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, без расширений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...