变体宏:粘贴标记的扩展

jdo*_*lan 4 c macros gcc clang variadic-macros

我想知道是否有可能"嵌套"可变宏调用.我只关心GCC和Clang.我的宏定义如下:

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

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

$(array, addObject, obj);
Run Code Online (Sandbox Code Playgroud)

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

/**
 * @see MutableSetInterface::addObjectsFromArray(MutableSet *, const Array *)
 */
static void addObjectsFromArray(MutableSet *self, const Array *array) {

    if (array) {
        for (size_t i = 0; i < array->count; i++) {
            $(self, addObject, $(array, objectAtIndex, i));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Win*_*ute 7

这是嵌套预处理器宏的常见问题.预处理器扩展规则相当晦涩; 相关的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)))
Run Code Online (Sandbox Code Playgroud)

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