首页 > 解决方案 > 是否可以动态定义_Generic 的关联列表?

问题描述

我有一个这样的模板:

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等的单曲。我的问题_Generic是似乎无法动态定义关联列表。实际上,我想要这样的东西:

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

而不是像这样手动定义每个新类型:

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

这是一个不起作用的代码示例:https ://ideone.com/HN7sst

标签: cgccgeneric-programmingc11

解决方案


我认为您想要做的事情可以通过可怕的“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++ 模板非常相似——函数做同样的事情但类型不同。

然后,您可以像这样编写 _Generic 宏:

void dummy (void* param){}
#define GENERIC_LIST(type, fmt) type: f_##type,
#define func(x) _Generic((x), SUPPORTED_TYPES(GENERIC_LIST) default: dummy)(x)

在这里定义通用 asoc。列出GENERIC_LIST,使用该type项目,但忽略其他所有内容。所以它扩展到例如int: f_int,

一个问题是旧的“尾随逗号”问题,我们不能像_Generic((x), int: f_int,)(x)逗号之后那样写 _Genericf_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,没有扩展。


推荐阅读