我对 C11 的 _Generic 机制感到很高兴 - 类型切换是我怀念 C++ 的功能。然而,事实证明它很难创作。
例如,给定函数:
bool write_int(int);
bool write_foo(foo);
bool write_bar(bar);
// bool write_unknown is not implemented
然后我可以写
#define write(X) _Generic((X), \
int : write_int, \
foo: write_foo, \
bar: write_bar, \
default: write_unknown)(X)
而且,只要我不尝试使用 &write 或将其传递给函数,我就可以调用 write(obj),并且只要 obj 是这些类型之一的实例,一切都很好。
然而,一般来说 foo 和 bar 彼此完全无关。它们在不同的标头中定义,很少(但偶尔)在单个源文件中一起使用。那么扩展到 _Generic 的宏应该写在哪里呢?
目前,我正在积累名为 write.h、equal.h、copy.h、move.h 的头文件,每个文件都包含一组函数原型和一个 _Generic。这是可行的,但并不出色。我不喜欢将程序中每种类型的列表收集到一个地方的要求。
我希望能够在头文件中定义类型 foo 以及函数 write_foo,并且以某种方式让客户端代码能够调用“函数”write。默认值看起来像是一个可以实现这一目标的向量。
我能在这个网站上找到的最接近的匹配是c11 泛型添加类型 https://stackoverflow.com/questions/9734982/c11-generic-adding-types它有一个部分解决方案,但它还不足以让我了解如何组合各种宏。
假设,在定义 write_bar 的头文件中的某个位置,我们有一个现有的宏定义:
#define write(x) _Generic((x), bar: write_bar, default: some_magic_here)(x)
或者我们可以省略尾随的 (x)
#define write_impl(x) _Generic((x), bar: write_bar, default: some_magic_here)
在这个标题的更下方,我想要一个处理 foo 或 bar 的 write() 版本。我认为它需要在默认情况下调用现有的宏,但我不相信预处理器能够重命名现有的写入宏。如果可以的话,以下内容可以发挥作用:
#ifndef WRITE_3
#define WRITE_3(X) write(x)
#undef write(x)
#define write(x) __Generic((x),foo: write_foo,default: WRITE_3)(x)
刚刚输入后,我可以看到一条前进的道路:
// In bar.h
#ifndef WRITE_1
#define WRITE_1(x) __Generic((x), bar: write_bar)
#elif !defined(WRITE_2)
#define WRITE_2(x) __Generic((x), bar: write_bar)
#elif !defined(WRITE_3)
#define WRITE_3(x) __Generic((x), bar: write_bar)
#endif
// In foo.h
#ifndef WRITE_1
#define WRITE_1(x) __Generic((x), foo: write_foo)
#elif !defined(WRITE_2)
#define WRITE_2(x) __Generic((x), foo: write_foo)
#elif !defined(WRITE_3)
#define WRITE_3(x) __Generic((x), foo: write_foo)
#endif
// In write.h, which unfortunately needs to be included after the other two
// but happily they can be included in either order
#ifdef WRITE_2
#define write(x) WRITE_1(x) WRITE_2(x) (x)
#elif
// etc
#endif
但这实际上不起作用,因为当 x 与参数列表不匹配时,我找不到使 WRITE_N(x) 扩展为空的方法。我看到错误
controlling expression type 'struct foo' not compatible with any generic association type
Or
expected expression // attempting to present an empty default clause
我相信在多个文件之间分发 write() 定义 |宏我需要解决上述任一问题。在默认情况下减少为无的 _Generic 子句将起作用,如果没有类型匹配则减少为无的子句也是如此。
更黑客的是,如果函数采用指向结构的指针而不是结构的实例,并且我提供 write_void(void*x) {(void)x;} 作为默认选项,则代码会编译并运行。但是,扩展写为
write(x) => write_void(x); write_foo(x); write_void(x);
显然本身就很糟糕,而且我真的不想通过指针传递所有内容。
那么,任何人都可以找到一种增量定义单个 _Generic“函数”的方法,即无需从它将映射的所有类型的列表开始吗?谢谢。