М.Солтерс прав; идентификаторы с одним символом подчеркивания зарезервированы. Если ваши макросы активны при включении чего-либо в реализацию, это может привести к конфликту, когда вы меньше всего этого ожидаете.
After compiling VS warns about ...
Я подозреваю, основываясь на этой цитате, что вы отлаживаете свои макросы, пытаясь их скомпилировать. Гораздо лучшим подходом было бы использование только препроцессора. В Microsoft вы можете сделать это, запустив cl /EP foo.h
в командной строке из консоли разработки (или после запуска VCVARSALL
для вашей конкретной реализации).
Теперь к макросам:
#define _COUNT_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define _COUNT(...) _COUNT_N("ignore", ## __VA_ARGS__, _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, _0)
#define _EXPAND(...) __VA_ARGS__
_COUNT
нужен шаг расширения, иначе он бесполезен. Это лучше:
#define COUNT_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define COUNT(...) EXPAND(COUNT_N( , __VA_ARGS__, _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, _0))
#define EXPAND(...) __VA_ARGS__
В настоящее время:
COUNT() COUNT(a) COUNT(a,b)
... расширяется до:
_1 _1 _2
Это технически правильно. COUNT()
имеет один аргумент (пустой). Причина, по которой это не возвращает _0
в Microsoft, заключается в шаге расширения... в первую очередь это позволяет макросу COUNT
работать. Если вы хотите, чтобы COUNT()
возвращал 0
, вам нужно добавить еще один уровень косвенности и использовать CALL
(поскольку список аргументов должен расширяться один раз, чтобы вызвать исключение запятой):
#define COUNT_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define COUNT_M(...) EXPAND(COUNT_N( __VA_ARGS__, _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, _0))
#define COUNT(...) CALL(COUNT_M,(, __VA_ARGS__))
#define CALL(X,Y) X Y
#define EXPAND(...) __VA_ARGS__
...и теперь COUNT()
возвращает _0
; имейте в виду, что это специфично для Microsoft.
Собираем это вместе
#define CONCAT_DETAIL(l, r) l##r
#define CONCAT(l, r) CONCAT_DETAIL(l, r)
#define COUNT_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define COUNT_M(...) EXPAND(COUNT_N( __VA_ARGS__, _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, _0))
#define COUNT(...) CALL(COUNT_M,(, __VA_ARGS__))
#define CALL(X,Y) X Y
#define EXPAND(...) __VA_ARGS__
#define CLASS_BODY(...) CONCAT(EXPAND(COUNT(__VA_ARGS__)),_DERIVED)(__VA_ARGS__)
CLASS_BODY()
CLASS_BODY(arg1)
CLASS_BODY(arg1,arg2)
... расширяется до:
_0_DERIVED()
_1_DERIVED(arg1)
_2_DERIVED(arg1,arg2)
Конечно, сейчас вы просто генерируете идентификаторы, начинающиеся с _
.
person
H Walters
schedule
25.10.2017
_COUNT
— это имя, зарезервированное для реализации, как и_DERIVED
и_EXPAND
. Почему люди всегда вставляют эти символы подчеркивания в начале, что специально запрещено, и никогда в конце? - person MSalters   schedule 25.10.2017_COUNT
был зарезервирован, и с тех пор изменил имена - person Matthew   schedule 25.10.2017