5

Here is a macro can calculate the count of arguments. and the code like:

#define Y_TUPLE_SIZE_II(__args) Y_TUPLE_SIZE_I __args
#define Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0

#define Y_TUPLE_SIZE_I(__p0,__p1,__p2,__p3,__p4,__p5,__p6,__p7,__p8,__p9,__p10,__p11,__p12,__p13,__p14,__p15,__p16,__p17,__p18,__p19,__p20,__p21,__p22,__p23,__p24,__p25,__p26,__p27,__p28,__p29,__p30,__p31,__n,...) __n

#define MPL_ARGS_SIZE(...) Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_ ## __VA_ARGS__ ## _Y_TUPLE_SIZE_POSTFIX,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))

// the running result ---------------------------------------

MPL_ARGS_SIZE(a,b,c,d,e,f,g)==7

MPL_ARGS_SIZE(a,b,c,d)==4

how to understand

#define Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0

and

Y_TUPLE_SIZE_PREFIX_ ## __VA_ARGS__ ## _Y_TUPLE_SIZE_POSTFIX

?

BTW, I know about ##(pound, pound) usage and the mechanism of #define Y_TUPLE_SIZE_I

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • 1
    That's a pretty crazy set of macros... – user253751 Jan 11 '16 at 01:55
  • You're just forming a bunch of empty arguments to pass (and 0). After you concatenate those, you get an argument list. This seems like slightly more than necessary for an argument counter macro, though. I guess the macro you're asking about probably handles the case of `MPL_ARGS_SIZE()` to give 0 instead of 1. – chris Jan 11 '16 at 02:05
  • @chris no, the empty arguments only come into play if no arguments are given. It's a special case. In the normal case, there are no empty arguments. – Tom Karzes Jan 11 '16 at 02:19
  • @TomKarzes, That's what I was getting at with the last sentence. The comment was kind of structured while building more and more of a mental model. – chris Jan 11 '16 at 02:57
  • I expanded my answer below to include a stripped-down solution that excludes the special case for zero arguments (which therefore results in 1 rather than 0 for that case). That should make it easier to understand. – Tom Karzes Jan 11 '16 at 02:59

1 Answers1

2

The PREFIX and POSTFIX macros are intended to make it give 0 when no arguments are given, i.e. MPL_ARGS_SIZE(). In this case, Y_TUPLE_SIZE_PREFIX_ and _Y_TUPLE_SIZE_POSTFIX are concatenated to produce Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX, which forces the result to 0.

In the general case, __VA_ARGS__ is non-empty, so the concatenation just expands to the same number of arguments that were given. This is followed by 32, ... 0.

In both cases, the arguments are wrapped in parentheses. Y_TUPLE_SIZE_II strips off these extra parentheses and passes the arguments on to Y_TUPLE_SIZE_I. Y_TUPLE_SIZE_I just expands to its 33rd argument, discarding the rest.

So if you give it 32 arguments, those 32 will be skipped and the number following them, 32, will be the result, as desired. If you give it 31 arguments, it will skip those 31, and the first number that follows, i.e. 32, and the result will be the next number, 31, again as desired.

If you give it a single argument, it will skip that argument and the 31 that follow it, and the result will be 1.

If you give it no arguments, the special case of Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX will come into play, which is 32 empty arguments followed by 0. The 32 empty arguments will be skipped, and the result will be 0.

The reason for the special case for no arguments is that without it, it would behave the same as the one-argument case. The following might help understand it better:

#define Y_TUPLE_SIZE_II(__args) Y_TUPLE_SIZE_I __args
#define Y_TUPLE_SIZE_I(__p0,__p1,__p2,__p3,__p4,__p5,__p6,__p7,__p8,__p9,__p10,__p11,__p12,__p13,__p14,__p15,__p16,__p17,__p18,__p19,__p20,__p21,__p22,__p23,__p24,__p25,__p26,__p27,__p28,__p29,__p30,__p31,__n,...) __n

#define MPL_ARGS_SIZE(...) Y_TUPLE_SIZE_II((__VA_ARGS__,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))

This is the original set of macros, but with all of the special-case handling for zero arguments removed. It works for everything but the zero-argument case, which returns 1 instead of 0.

In order to handle zero arguments, it sandwiches the argumement list between the prefix and postfix macros. If the result expands to Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX, then the argument list was empty, and the special case comes into play.

Tom Karzes
  • 22,815
  • 2
  • 22
  • 41
  • well, the method `Y_TUPLE_SIZE_II((__VA_ARGS__,32...0))` was understand easier. But come back to `#define MPL_ARGS_SIZE(...) Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_ ## __VA_ARGS__ ## _Y_TUPLE_SIZE_POSTFIX,...)` for example, if the arguments was a, b, c, how about is the situation when expanded `MPL_ARGS_SIZE(a, b, c) ` ? It seems `Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_a,b,c_Y_TUPLE_SIZE_POSTFIX, ...0))`, of course it's a incorrect statements, how to understand it ? – William Sterling Jan 11 '16 at 06:05
  • Right, in the case of one or more arguments, the first and last arguments are altered by the prefix and postfix strings, but it doesn't matter since the only purpose the arguments serve is to occupy an argument position. They're all discarded in the final result. – Tom Karzes Jan 11 '16 at 06:13
  • oooops, I am lost before... `Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_a,b,c_Y_TUPLE_SIZE_POSTFIX, ...0)` will be expand as `Y_TUPLE_SIZE_I(Y_TUPLE_SIZE_PREFIX_a,b,c_Y_TUPLE_SIZE_POSTFIX, ...0)`, the PREFIX_a, b, c_POSTFIX both as the parameter of `Y_TUPLE_SIZE_I` macro. tks. – William Sterling Jan 11 '16 at 06:34