Counting variadic arguments
The following code is simplified version of a code snippet which I’ve found on stack overflow site.
#define VA_COUNT0(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, …) N
Being able to count at preprocessing stage, means many things.
There’re a bunch of subtle, dirty expressions related to variadic macro or function in C.
A direct example is to pass the number of arguments to a variadic function.
#define f(…) f_(VA_COUNT(__VA_ARGS__), __VA_ARGS__)
@ It seems that boost has similar functionality, but personally I avoid boost because it has too many “interdependencies”… Don’t know how boost does it.
Defining VA_MAP as below, enables a similar effect to map() of python or perl.
#define CONCAT(x, y) CONCAT0(x, y)
#define CONCAT0(x, y) x##y
#define VA_MAP(f, …) CONCAT(VA_MAP_, VA_COUNT(__VA_ARGS__))(f, __VA_ARGS__)
#define VA_MAP_9(f, x, …) f(x), VA_MAP_8(f, __VA_ARGS__)
#define VA_MAP_8(f, x, …) f(x), VA_MAP_7(f, __VA_ARGS__)
#define VA_MAP_7(f, x, …) f(x), VA_MAP_6(f, __VA_ARGS__)
#define VA_MAP_6(f, x, …) f(x), VA_MAP_5(f, __VA_ARGS__)
#define VA_MAP_5(f, x, …) f(x), VA_MAP_4(f, __VA_ARGS__)
#define VA_MAP_4(f, x, …) f(x), VA_MAP_3(f, __VA_ARGS__)
#define VA_MAP_3(f, x, …) f(x), VA_MAP_2(f, __VA_ARGS__)
#define VA_MAP_2(f, x, …) f(x), VA_MAP_1(f, __VA_ARGS__)
#define VA_MAP_1(f, x) f(x)
A sample example is to pass the size of an argument along with the argument itself.
#define WITH_SIZE(x) sizeof(x), x
#define f(…) f_(VA_MAP(WITH_SIZE, __VA_ARGS__), 0)
Note that this example is not that usable, because string literal is passed as a character pointer, but sizeof() of string literal returns the length of string, not sizeof(const char *)
Here’s another bonus tip.
Define a macro which selects a first argument of variadic macro,
then it can be used to avoid dangling comma problem without using ,## extension of gcc.
#define VA_FIRST0(arg, …) arg
For example,
#define check(cond, …) \
do { if (!cond) fail(__FILE__, __LINE__, ##__VA_ARGS__); } while (0)
Instead, the following code is more portable, although it needs fail() to have an extra dummy argument.
#define check(/* cond, */ …) \
do { if (!VA_FIRST(__VA_ARGS__)) fail(__FILE__, __LINE__, __VA_ARGS__); } while (0)
- moonz's blog
- Login to post comments
- 한국어