注意:我对使用 GCC 语句表达式不感兴趣!
我正在使用红黑树实现一个集合数据结构,并使其适用于多种类型,我正在使用宏。
这是节点的定义:
typedef struct {
bool colour;
void* val;
void* parent;
void* left;
void* right;
}* set;
我想创建一个宏函数
set_contains(s, t)
,如果t
在集合s
中,它将“返回”一个真实的表达式。我所说的“返回”是指我可以这样使用它:
if(set_contains(my_set, 6)) {
...
}
例如,如果 x 是奇数,则以下宏“返回”真表达式:
#define isOdd(x) \
/* notice the lack of semicolon! */ \
(bool)((x)&1)
我的
set_contains
宏如下所示:
#define set_contains(s, t) \
do { \
set it = s; \
while(it && *(typeof((t))*)it->val != (t)) { \
if((t) < *(typeof((t))*)it->val) it = it->left; \
else it = it->right; \
} \
/* This is what I want to "return" */ \
(bool)it; \
} while(0)
如何在宏末尾添加
(bool)it
,以便我可以将整个内容用作表达式(如 isOdd
宏)? do while
是必要的,因为我需要定义一个临时变量 (it
) 来迭代集合。当然,我不能在 it
之后使用 while
,因为它在该范围内未定义。再一次,我想在不使用 GCC 语句表达式的情况下实现这一目标。
仅使用宏不足以实现此目的;也许最不痛苦的解决方案是创建多个类型感知函数并使用
_Generic
选择正确的函数:
#define set_contains(set, val) _Generic((val), \
int: set_contains_int, \
double: set_contains_double, \
char *: set_contains_string, \
/* any additional types */ \
)(set, val)
...
bool set_contains_int(set s, int val) { ... }
bool set_contains_double(set s, double val) { ... }
bool set_contains_string(set s, char *val) { ... }
...
if (set_contains(set, 6))
// do something
_Generic
指令根据val
的type选择正确的函数。 缺点是你最终会得到很多重复的逻辑。
或者,您可以创建一个作为回调传递的比较器函数:
int cmp_int( const void *l, const void *r )
{
const int *il = l;
const int *ir = r;
if ( *l < *r )
return -1;
else if ( *l > *r )
return 1;
return 0;
}
bool set_contains(set s, const void *val, int (*cmp)(const void *, const void *))
{
...
while( it && cmp(it->val, val) != 0 )
{
if ( cmp(it->val, val) < 0 )
it = it->left;
else
it = it->right;
}
return it != NULL;
}
这将被称为
int val = 6;
if (set_contains(set, &val, cmp_int))
...
但这意味着你不能直接用
set_contains
作为文字来调用 val
(像 set_contains(set, 6, cmp_int)
这样的东西是行不通的)。 为此,您仍然必须创建类型感知的前端,例如:
bool set_contains_int(set s, int val)
{
return set_contains(s, &val, cmp_int);
}
对于这样的事情,我更喜欢第二种方法(在我看来,减少重复工作),但与真正的类型多态性相比,这两种方法都有点恶心。