Возможна ли подстановка вариативного макроса для каждого аргумента?

Сейчас я прочитал довольно много вопросов на SO о вариативных макросах, но, похоже, никто не ответил на самый простой вопрос:

#define IDENTITY(x) x
#define IDENTITY_FOR_ALL(...) ???

Есть ли способ заставить IDENTITY_FOR_ALL расширяться до IDENTITY(X) для всех аргументов? Возможно ли это также для произвольного количества аргументов?


person iFreilicht    schedule 20.10.2014    source источник
comment
Не могли бы вы привести образец ввода и то, к чему он должен быть предварительно обработан?   -  person chris    schedule 21.10.2014
comment
Вы уверены, что не можете использовать вариативный шаблон вместо макроса?   -  person Deduplicator    schedule 21.10.2014
comment
@chris IDENTITY - это результат. Я только хочу, чтобы он был предварительно обработан для другого макроса, ничего больше.   -  person iFreilicht    schedule 21.10.2014
comment
@ Дедупликатор да. В моем случае макрос с одним аргументом будет использоваться для определения значения перечисления. Мне нужно выполнить работу по замене текста в препроцессоре.   -  person iFreilicht    schedule 21.10.2014
comment
Вы хотите, чтобы IDENTITY_FOR_ALL(x,y,z,w) расширилось до x,y,z,w?   -  person David Young    schedule 21.10.2014
comment
@DavidYoung нет, я хочу, чтобы он расширился до x y z w   -  person iFreilicht    schedule 21.10.2014


Ответы (2)


Для вариативных макросов не существует такой вещи, как расширение пакета, как для вариативных шаблонов.

Однако вы можете использовать Boost.Preprocessor (или его методы).

Если вам не нужны запятые между элементами, используйте

#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>

#define ID_OP(_, func, elem) func(elem)
#define APPLY_TO_ALL(func, ...)                \
    BOOST_PP_SEQ_FOR_EACH(                     \
        ID_OP, func,                           \
        BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)  \
    )

// example call:

#define SomeTransformation(x) #x // stringize the argument

APPLY_TO_ALL(SomeTransformation, 1, 2, 3) // expands to "1" "2" "3"

Демо. С запятыми:

#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>

#define ID_OP(_, func, elem) func(elem)
#define APPLY_TO_ALL(func, ...)               \
    BOOST_PP_SEQ_ENUM(                        \
    BOOST_PP_SEQ_TRANSFORM(                   \
        ID_OP, func,                          \
        BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__) \
    ))

// example call:

APPLY_TO_ALL(SomeTransformation, 1, 2, 3) // expands to "1", "2", "3"

Демо. Проверьте вывод препроцессора с помощью g++ -std=c++11 -E -P file.

person Columbo    schedule 20.10.2014
comment
Черт, мне нужно научиться SEQ, когда мне нужен доступ к каждому элементу. TUPLE не имеет FOR_EACH - person chris; 21.10.2014
comment
@chris Да, SEQ действительно сексуальны (без каламбура). - person Columbo; 21.10.2014
comment
похоже, что первый (который я хочу) не работает под VC2013. identifier "BOOST_PP_IIF_0" is undefined :( - person iFreilicht; 21.10.2014
comment
@iFreilicht Вы уверены, что правильно включили все заголовки? Редактировать: Оглядываясь назад, я не думаю, что это проблема. - person Columbo; 21.10.2014
comment
@Loopunroller Нашел проблему. BoostPP неправильно определил свои макросы variadics. в config.hpp он проверяет не только _MSC_VER, но и __EDG__ (что бы это ни было). Если последний определен, он не определяет BOOST_PP_VARIADICS или BOOST_PP_VARIADICS_MSVC. после этого до включения заголовков все работает как положено. - person iFreilicht; 21.10.2014

Предполагая, что вам нужно решение PP, вы можете использовать BOOST_PP_REPEAT:

//invoke IDENTITY_FOR_ALL_MACRO with each index and the given tuple
#define IDENTITY_FOR_ALL(...)                   \
    BOOST_PP_REPEAT(                            \
        BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),    \
        IDENTITY_FOR_ALL_MACRO,                 \
        BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__) \
    )

//use the index to access the right element of the passed tuple
#define IDENTITY_FOR_ALL_MACRO(z, n, data) \
    IDENTITY(BOOST_PP_TUPLE_ELEM(n, data))

IDENTITY_FOR_ALL(abc, 123, "woopee")
//translated to abc 123 "woopee"

Было бы довольно просто превратить это в более общий макрос, который берет макрос для вызова и список отдельных аргументов для передачи один за другим, если вам нужно сделать это с несколькими разными макросами, а не только IDENTITY.

Я не уверен на 100%, что вы подразумеваете под произвольным числом аргументов, но если вы хотите вызывать IDENTITY с двумя аргументами вместо одного, вы можете изменить нижний макрос, чтобы использовать BOOST_PP_MUL и BOOST_PP_INC для доступа к "2n "th и "2n+1"th элементов кортежа, а затем вызывать макрос вдвое меньше, чем в вызове REPEAT.

person chris    schedule 20.10.2014
comment
+1 #include <boost/preprocessor.hpp> boost.org/doc/libs/1_43_0 /libs/препроцессор/doc/index.html - person Deduplicator; 21.10.2014
comment
Под произвольным количеством аргументов я подразумеваю именно это. Я видел несколько специализированных решений для распаковки вариативных макросов, которые включали определение макросов для каждого отдельного количества аргументов, поэтому я хотел знать, есть ли лучшее решение. Видимо есть. - person iFreilicht; 21.10.2014
comment
@iFreilicht, ах, да, Boost уже сделал это за вас. Только REPEAT представляет собой что-то вроде 3 * 256 отдельных макросов плюс один для выбора правильных макросов для вызова. - person chris; 21.10.2014