变体宏:粘贴标记的扩展

我想知道是否可以“嵌套”可变宏调用。 我只关心GCC和Clang。 我的宏定义如下所示:

/** * @brief Invoke an instance method. */ #define $(obj, method, ...) \ ({ \ typeof(obj) _obj = obj; \ _obj->interface->method(_obj, ## __VA_ARGS__); \ }) 

我用它在我的OO框架中方便地调用“实例方法”( https://github.com/jdolan/objectively ):

 $(array, addObject, obj); 

工作老板。 不幸的是,我还没有想出一种允许嵌套这些调用的方法,这在某些情况下非常有用; 例如:

 /** * @see MutableSetInterface::addObjectsFromArray(MutableSet *, const Array *) */ static void addObjectsFromArray(MutableSet *self, const Array *array) { if (array) { for (size_t i = 0; i count; i++) { $(self, addObject, $(array, objectAtIndex, i)); } } } 

上面的嵌套可变参数宏调用无法编译,因为内部调用永远不会扩展。 是否有可能解决这个问题,或者我已经将预处理器滥用到了极限? 🙂

这是嵌套预处理器宏的常见问题。 预处理器扩展规则相当晦涩; 相关的tl; dr是宏在层中扩展。 解决方法是添加一个可以扩展参数的间接层:

 #define MI(obj, method, ...) \ ({ \ typeof(obj) _obj = obj; \ _obj->interface->method(_obj, ## __VA_ARGS__); \ }) #define M(obj, method, ...) MI(obj, method, __VA_ARGS__) // This will now expand properly. M(self, addObject, M(array, objectAtIndex, M(foo, bar, i))) 

旁注:请注意$不是C的基本源字符集的一部分; 使用它可能不会是便携式的。