Я экспериментировал с макросами C ++ 11 variadac.
Я пытался применить другой макрос для каждого аргумента в списке.
Это моя первая попытка:
#define APPLY_CHAIN(first, ...) APPLY_ACT(first) APPLY_CHAIN( __VA_ARGS__ )
К сожалению, это не сработало.
В конце концов я получил его на работу. Но это было немного запутанно и имеет предел ‘n’ (где ‘n’ — максимальный размер, для которого я готов печатать макросы).
#define COUNT_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define COUNT(...) COUNT_N( __VA_ARGS__, 10, 9, 8, 7, 6, 5 ,4, 3, 2, 1)
#define BUILD_CHAIN_1(_1) APPLY_ACT(_1)
#define BUILD_CHAIN_2(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_1(__VA_ARGS__)
#define BUILD_CHAIN_3(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_2(__VA_ARGS__)
#define BUILD_CHAIN_4(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_3(__VA_ARGS__)
#define BUILD_CHAIN_5(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_4(__VA_ARGS__)
#define BUILD_CHAIN_6(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_5(__VA_ARGS__)
#define BUILD_CHAIN_7(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_6(__VA_ARGS__)
#define BUILD_CHAIN_8(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_7(__VA_ARGS__)
#define BUILD_CHAIN_9(_1, ...) APPLY_ACT(_1) BUILD_CHAIN_8(__VA_ARGS__)
#define BUILD_CHAIN_10(_1,...) APPLY_ACT(_1) BUILD_CHAIN_9(__VA_ARGS__)#define BUILD_CHAIN_INC( CT, ...) BUILD_CHAIN_ ## CT (__VA_ARGS__)
#define BUILD_CHAIN( CT, ...) BUILD_CHAIN_INC(CT, __VA_ARGS__)
#define APPLY_CHAIN(...) BUILD_CHAIN( COUNT(__VA_ARGS__), __VA_ARGS__)
#define APPLY_ACT(X) #X
#include <iostream>
int main()
{
std::cout << APPLY_CHAIN(1,2,3,4,5) << "\n";
}
Итак, мой вопрос: я упускаю что-то простое, что позволило бы мне iterate
по цепочке аргументов?
Было бы появиться эти рекурсивные макросы все еще невозможны, так как препроцессор занимает только один проход по источнику.
Могу поспорить, что вы могли бы сделать явную циклическую конструкцию, используя пустышку #include
используя условную охрану (что, возможно, что boost.preprocessor заканчивает тем, что делал.)
Ваше решение проблемы с количеством аргументов такое же, как и решение, опубликованное на [comp.lang.c] (IIRC) Лораном Денио в январе 2006 года.
Модифицированный для работы также с Visual C ++, его подсчет аргументов выглядит так:
#pragma once
/*
* The PP_NARG macro evaluates to the number of arguments that have been
* passed to it.
*
* Laurent Deniau, "__VA_NARG__," 17 January 2006, <comp.std.c> (29 November 2007).
* https://groups.google.com/forum/?fromgroups=#!topic/comp.std.c/d-6Mj5Lko_s
*/
// Added workaround for silly MSVC bug that yields "too few parameters" warning.
// - Alf
#include <progrock/cppx/macro/invoke.h> // CPPX_INVOKE
#include <progrock/cppx/macro/concat.h> // CPPX_CONCAT
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
#define PP_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,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
#if 0
#define PP_NARG_(...) PP_ARG_N( __VA_ARGS__ )
#define PP_NARG( ...) PP_NARG_( __VA_ARGS__, PP_RSEQ_N() )
#else
#define PP_NARG_(...) CPPX_INVOKE( PP_ARG_N, (__VA_ARGS__) )
#define PP_NARG(...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#endif
CPPX_CONCAT
макрос:
#pragma once
#define CPPX_CONCAT__( a, b ) a ## b
#define CPPX_CONCAT_( a, b ) CPPX_CONCAT__( a, b )
#define CPPX_CONCAT( a, b ) CPPX_CONCAT_( a, b )
CPPX_INVOKE
макрос:
#pragma once
#define CPPX_INVOKE( macro, args ) macro args
Пример использования:
#pragma once
#include <progrock/cppx/macro/nargs.h> // CPPX_NARGS, CPPX_CONCAT
#define CPPX_IS_UNUSED_( name ) \
(void) name; struct name
#define CPPX_IS_UNUSED_1( a ) \
CPPX_IS_UNUSED_( a )
#define CPPX_IS_UNUSED_2( a, b ) \
CPPX_IS_UNUSED_1( a ); CPPX_IS_UNUSED_( b )
#define CPPX_IS_UNUSED_3( a, b, c ) \
CPPX_IS_UNUSED_2( a, b ); CPPX_IS_UNUSED_( c )
#define CPPX_IS_UNUSED_4( a, b, c, d ) \
CPPX_IS_UNUSED_3( a, b, c ); CPPX_IS_UNUSED_( d )
#define CPPX_IS_UNUSED_5( a, b, c, d, e ) \
CPPX_IS_UNUSED_4( a, b, c, d ); CPPX_IS_UNUSED_( e )
#define CPPX_IS_UNUSED( ... ) \
CPPX_INVOKE( CPPX_CONCAT( CPPX_IS_UNUSED_, CPPX_NARGS( __VA_ARGS__ ) ), ( __VA_ARGS__ ) )
#define CPPX_IS_INTENTIONALLY_UNUSED CPPX_IS_UNUSED
Как это видно, основной ключ к разгадке — не использовать рекурсию (по крайней мере, не напрямую), а вместо этого повторять код вручную для каждого числа аргументов.
Я считаю, что рекурсивные макросы формально невозможны. Тем не менее, немногие компиляторы согласуются в этой области, и несколько лет назад, по крайней мере, вы действительно могли убедить компиляторы WIndows сделать рекурсивное подстановку макросов. Насколько я помню, это была методика, изначально использовавшаяся в коде, который в конечном итоге стал библиотекой препроцессора Boost (теперь она использует формально допустимый код, централизуя большой список обработчиков, зависящих от количества аргументов, за исключением обходных путей для специфических для компилятора особенностей) ,
Такое повторение кода, скорее всего, можно автоматизировать с помощью библиотеки препроцессора Boost, но тогда вы будете использовать Boost и для других вещей (возможно, смысл в том, чтобы избежать зависимости от большой библиотеки, такой как Boost, по крайней мере, это было моей мотивацией, когда я писал выше).
Отказ от ответственности: я не повторял этот код перед публикацией, и я не могу вспомнить, был ли он в состоянии изменения, или как. Но это показывает общие принципы.
смотреть на Boost.Preprocessor. конкретно BOOST_PP_SEQ_FOLD_LEFT. Тебе понадобиться BOOST_PP_VARIADIC_TO_SEQ.
Что-то вроде
#include <boost/preprocessor.hpp>
#include <iostream>
#define OP(d, state, x) state BOOST_PP_STRINGIZE(x)
#define APPLY_CHAIN(...) BOOST_PP_SEQ_FOLD_LEFT( OP, BOOST_PP_EMPTY() , BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__) )
int main() {
std::cout << APPLY_CHAIN(1,2,3,4,5) << std::endl;
}
//expands to std::cout << "1" "2" "3" "4" "5" << std::endl;