Я видел несколько вопросов, спрашивающих о вариации FOR_EACH
макро. Однако, к сожалению, предоставленные ответы несовместимы с VC ++ 10, так как он расширяет __VA_ARGS __ в качестве одного аргумента при передаче другому макросу. Пожалуйста, кто-нибудь может предоставить C ++ 11-совместимую (следовательно, совместимую с версией) версию, которая все еще работает с VC ++ 10. Возможно, используя «обходной путь», который часто упоминается, #define EXPAND(x) x
Однако я не знаю, где это поставить, чтобы получить, например, последнюю обобщенную часть этот ответ работать в VC ++ 10.
Чтобы уточнить, предполагаемое поведение для FOR_EACH(x, a, b, ...)
производить x(a) x(b), ...
где х другой макрос.
Теперь, точно поняв, как работает ошибка компилятора VC ++ 10, я смог сам создать такой макрос, основываясь на последней части этот ответ.
#define EXPAND(x) x
#define FOR_EACH_1(what, x, ...) what(x)
#define FOR_EACH_2(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_1(what, __VA_ARGS__))
#define FOR_EACH_3(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_2(what, __VA_ARGS__))
#define FOR_EACH_4(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_3(what, __VA_ARGS__))
#define FOR_EACH_5(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_4(what, __VA_ARGS__))
#define FOR_EACH_6(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_5(what, __VA_ARGS__))
#define FOR_EACH_7(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_6(what, __VA_ARGS__))
#define FOR_EACH_8(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_7(what, __VA_ARGS__))
#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) EXPAND(FOR_EACH_ARG_N(__VA_ARGS__))
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define CONCATENATE(x,y) x##y
#define FOR_EACH_(N, what, ...) EXPAND(CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__))
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
Пример использования:
#define callMember(o, f) o.f();
#define callMember_o(f) callMember(o, f)
FOR_EACH(callMember_o, doSomething, doSomethingElse);
такой же как
o.doSomething(); o.doSomethingElse();
Это решение аналогично решению в связанном ответе, за исключением того, что список аргументов переменной длины нулевой длины в FOR_EACH(what, x, ...)
при вызове с одним элементом возникла ложная запятая, которая заставляет FOR_EACH_NARG считать 2 аргумента вместо 1 аргумента, и EXPAND
макрос обходной путь используется.
Ошибка в VC ++ 10 заключается в том, что если __VA_ARGS__
передается макросу в определении макроса variadic, он оценивается после подстановки в макрос, что приводит к тому, что несколько разделенных запятыми аргументов рассматриваются как один. Чтобы обойти это, вы должны отложить оценку аргумента до __VA_ARGS__
подставляется, оборачивая вызов макроса в EXPAND
, заставляя вызов макроса оцениваться как строку, подставляя __VA_ARGS__
сделать это. Только после замены в EXPAND
это вызываемый макрос, к которому точка вариативных аргументов уже подставлена.
Постскриптум Я был бы признателен, если кто-нибудь может предложить метод для компактного производства FOR_EACH_N
макросы для гораздо больших значений N
,
Других решений пока нет …