Variadic macros: expansion of pasted tokens

571 Views Asked by At

I'm wondering if it's possible to "nest" variadic macro invocations. I'm only truly concerned with GCC and Clang. My macro definition looks like this:

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

I use this to conveniently call "instance methods" in my OO framework (https://github.com/jdolan/objectively):

$(array, addObject, obj);

Works boss. Unfortunately, I haven't yet figured out a way to allow nesting of these calls, which would be very useful in some situations; e.g.:

/**
 * @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));
        }
    }
}

The nested variadic macro invocation above fails to compile because the inner invocation is never expanded. Is it possible to fix this, or have I already abused the preprocessor to its limits? :)

1

There are 1 best solutions below

6
On BEST ANSWER

This is a common problem with nested preprocessor macros. Preprocessor expansion rules are fairly arcane; the relevant tl;dr is that macros are expanded in layers. The workaround is to add a layer of indirection in which the parameter can be expanded:

#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)))

Side note: be aware that $ is not part of C's basic source character set; using it will probably not be portable.