Search code examples
cc-preprocessormetaprogrammingx-macros

Cartesian product of X-macro list with itself


Suppose that, in C, I have an list of things specified using X-macros. For example,

#define TYPES(X, ...) \
  X(__VA_ARGS__, i, int) \
  X(__VA_ARGS__, j, unsigned int) \
  X(__VA_ARGS__, l, long) \
  X(__VA_ARGS__, m, unsigned long)

If I add a second copy of that macro (call it TYPES_), it’s not hard to generate some code for each pair of things in the list; for example:

#define TYPES_(X, ...) \
  X(__VA_ARGS__, i, int) \
  X(__VA_ARGS__, j, unsigned int) \
  X(__VA_ARGS__, l, long) \
  X(__VA_ARGS__, m, unsigned long)
#define CAST(FROMCH, FROMTY, TOCH, TOTY) \
  TOTY FROMCH ## to ## TOCH (FROMTY x) { return (TOTY)x; }
TYPES_(TYPES, CAST)

However, if I use TYPES instead of the duplicate TYPES_, this code won’t work, because (I think?) the top-level expansion TYPES then contains an occurrence of TYPES itself, which is not permitted to expand further.

Is there a way to convince the C preprocessor to generate code for a cartesian product of a list with itself, like here, without specifying the list twice? It’s probably possible with chaos/order-pp-style insanity that accomplishes a lot of expansions through billion laughs-like hacks, but I’d prefer not to resort to that.


Solution

  • You can use an EXPAND macro to perform delayed expansion. Rather clumsily:

    #define EXPAND(X) X
    #define TYPES1() TYPES
    #define TYPES2(...) TYPES1 EXPAND(())(__VA_ARGS__)
    EXPAND(TYPES(TYPES2, CAST))
    

    Demo.