0
votes

I want a macro that takes any even number of parameters, stitches each pair together, adds some name to the end, let's say Type, and then passes them as template arguments to some type, let's call it CompileTimeList. So I would give it something like this:

MACRO( \
  First,Set, \
  Second,Type, \
  Third,Thing)

and it would expand to:

CompileTimeList<
  FirstSetType,
  SecondTypeType,
  ThirdThingType>

The naive solution would be a variadic recursive template, which is not allowed:

Can we have recursive macros?

I could manually hack together a macro using this methodology:

Macro recursive expansion to a sequence

But it would be limited to however many parameters I've defined. I want to be able to expand any length of parameters. Is this possible in C++11? I also have Boost 1.55 available, which wasn't mentioned in the other questions.

In order to attempt to implement chris' answer, I've written the following program:

  1 #include <boost/preprocessor.hpp>
  2
  3 #include <vector>
  4 #include <algorithm>
  5
  6 #define MACRO(...)  \
  7     std::find( \
  8     BOOST_PP_ENUM( \
  9         BOOST_PP_DIV(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 2), \
 10         ENUM_MACRO, \
 11         BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__) \
 12     ) \
 13     )
 14
 15 #define ENUM_MACRO(z, n, data) \
 16     BOOST_PP_CAT( \
 17         BOOST_PP_CAT( \
 18             BOOST_PP_TUPLE_ELEM(BOOST_PP_MUL(n, 2), data), \
 19             BOOST_PP_TUPLE_ELEM(BOOST_PP_INC(BOOST_PP_MUL(n, 2)), data) \
 20         ), \
 21         Type \
 22     )
 23
 24
 25 typedef int FirstNameType;
 26 typedef std::vector<int>::iterator SecondNameType;
 27 typedef std::vector<int>::iterator ThirdNameType;
 28
 29 int main()
 30 {
 31     std::vector<int>();
 32     auto it = MACRO(First, Name, Second, Name, Third, Name);
 33     return 0;
 34 }

Which produces an avalanche of errors relating to the use of commas, starting with:

test.cpp: In function ‘int main()’: src/boost/boost/preprocessor/punctuation/comma.hpp:19:27: error: expected primary-expression before ‘,’ token # define BOOST_PP_COMMA() ,

1
I would instead go for MACRO((First, Set), (Second, Type), (Third, Thing)) and use BOOST_PP_TUPLE_*.chris
@chris Thanks, I wasn't aware of this. But how do you get around the "reursion isn't allowed" problem?quant
@Jason: By recursing anyway: File x.h: #include "x.h"...Kerrek SB
@KerrekSB I'm not sure I follow. You mean I should #include recursively?quant
@Jason, Boost provides utilities for enumerating sequences. Have a look through boost.org/doc/libs/1_55_0/libs/preprocessor/doc/index.htmlchris

1 Answers

1
votes

Your desired syntax can be achieved through Boost with a couple macros:

#define BOOST_PP_VARIADICS
#include <boost/preprocessor.hpp>

//The main part is BOOST_PP_ENUM, which loops the number of arguments / 2 times.
//Each loop, ENUM_MACRO is called with the index and a tuple containing the arguments.
//A comma is inserted between all expansions of ENUM_MACRO.
#define MACRO(...)  \
    CompileTimeList< \
    BOOST_PP_ENUM( \
        BOOST_PP_DIV(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 2), \
        ENUM_MACRO, \
        BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__) \
    ) \
    >

//Since it's called #args/2 times, we multiply the index by 2.
//All it does is concatenate the first in its pair with the second, and then to Type.
#define ENUM_MACRO(z, n, data) \
    BOOST_PP_CAT( \
        BOOST_PP_CAT( \
            BOOST_PP_TUPLE_ELEM(BOOST_PP_MUL(n, 2), data), \
            BOOST_PP_TUPLE_ELEM(BOOST_PP_INC(BOOST_PP_MUL(n, 2)), data) \
        ), \
        Type \
    )


MACRO(a, b, c, d) //CompileTimeList< abType , cdType >

See it work here.

While in its current state, this macro will simply ignore the last argument in an odd-numbered list, it is possible to produce an error with a simple static_assert, or to do something special with the last argument if so desired.