5

I read quite a few questions on SO about variadic macros now, but it doesn't seem like anyone answered the most simple question:

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

Is there a way to make IDENTITY_FOR_ALL expand to IDENTITY(X) for all arguments? Is it also possible for arbitrary numbers of arguments?

a3f
  • 8,517
  • 1
  • 41
  • 46
iFreilicht
  • 13,271
  • 9
  • 43
  • 74

2 Answers2

5

There is no such thing as a pack expansion for variadic macros as there is for variadic templates.

You could use Boost.Preprocessor (or its methods) though.

If you don't want any commas between the elements, use

#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"

Demo. With commas:

#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"

Demo. Check the preprocessor output with g++ -std=c++11 -E -P file.

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • Dang I need to learn to SEQ when I need access to each element. TUPLE doesn't have a FOR_EACH – chris Oct 20 '14 at 21:36
  • @chris Yeah, SEQs are really sexy (no pun intended). – Columbo Oct 20 '14 at 21:47
  • it seems like the first one (which is the one I want) doesn't work under VC2013. `identifier "BOOST_PP_IIF_0" is undefined` :( – iFreilicht Oct 20 '14 at 22:55
  • @iFreilicht Are you sure you included all the headers appropriately? Edit: In hindsight I don't think that's the problem. – Columbo Oct 20 '14 at 23:18
  • @Loopunroller Found the issue. BoostPP defined its variadics macros wrong. in `config.hpp`, it not only checks `_MSC_VER`, but also `__EDG__` (whatever that is). If latter is defined, it doesn't define `BOOST_PP_VARIADICS` or `BOOST_PP_VARIADICS_MSVC`. after doing that before including the headers, everything works as expected. – iFreilicht Oct 21 '14 at 09:32
1

Assuming you need a PP solution, you can use 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"

It would be decently straightforward to turn this into a more general macro that takes a macro to invoke and the list of single arguments to pass one by one if you need to do this with several different macros and not just IDENTITY.

I'm not 100% sure what you mean by an arbitrary number of arguments, but if you want to invoke IDENTITY with two arguments at a time instead of one, you can change the bottom macro to use BOOST_PP_MUL and BOOST_PP_INC to access the "2n"th and "2n+1"th elements of the tuple, and then invoke the macro only half as many times in the REPEAT call.

chris
  • 60,560
  • 13
  • 143
  • 205
  • +1 `#include ` http://www.boost.org/doc/libs/1_43_0/libs/preprocessor/doc/index.html – Deduplicator Oct 20 '14 at 21:34
  • By arbitrary number of arguments I mean exactly that. I've seen some specialised solutions for variadic macro unpacking that involved defining macros for every single number of arguments, so I wanted to know if there's a better solution. Apparently there is. – iFreilicht Oct 20 '14 at 21:41
  • @iFreilicht, Ah, yeah, Boost already did that for you. `REPEAT` alone is something like 3*256 separate macros plus ones to choose the right macros to invoke. – chris Oct 20 '14 at 21:43