I have following code:
#include
#include
template< int I, int J >
struct Base
{
};
#define SEQ ( 1 ) ( 2 ) ( 3 ) ( 4 )
#define OP( s, data, elem ) Base< elem, elem >
struct Derived
: BOOST_PP_SEQ_ENUM( BOOST_PP_SEQ_TRANSFORM( OP, nil, SEQ ) )
{
};
The Derived has bases classes generated from a sequence (SEQ). The bases classes themselves are instantiations of Base template type. I expected the code to be preprocessed into something like (just the important part):
struct Derived
: Base< 1, 1 >, Base< 2, 2 >, Base< 3, 3 >, Base< 4, 4 >
{
};
but instead it is preprocessed into:
struct Derived
: Base< 1, Base< 2, Base< 3, Base< 4
{
};
This obviously is caused by Base being template with to parameters and thus having a comma.
Adding parenthesis around Base in OP solves the issue by generating expected code fully. But it still does not compile because parenthesis are not allowed in that place (base classes list).
Is there any other workaround? How to deal with it?
There are two ways you can solve this. The first is to use `BOOST_PP_SEQ_FOR_EACH_I`, like this, which is the simplest solution:
#define OP(r, data, i, x) BOOST_PP_COMMA_IF(i) Base
struct Derived
: BOOST_PP_SEQ_FOR_EACH_I(OP, ~, SEQ)
{
...
};
However, if you have more complex use cases, where you need to process variadic sequences, you can use sequence iteration directly, like this:
#define OP(x) Base< x, x >
#define TRANSFORM(x) BOOST_PP_CAT(TRANSFORM_0 x, _END)
#define TRANSFORM_0(...) (OP(__VA_ARGS__)) TRANSFORM_1
#define TRANSFORM_1(...) (OP(__VA_ARGS__)) TRANSFORM_0
#define TRANSFORM_0_END
#define TRANSFORM_1_END
This will let you define sequence with multiple parameters instead, perhaps like this:
#define SEQ (1, 2) (3, 4) (5, 6)
#define OP(x, y) Base< x, y >
Then finally, you can use sequence iteration to define `PP_SEQ_ENUM` that works on variadic sequences as well:
#define PP_SEQ_ENUM(x) BOOST_PP_CAT(PP_SEQ_ENUM_0 x, _END)
#define PP_SEQ_ENUM_0(...) __VA_ARGS__ PP_SEQ_ENUM_1
#define PP_SEQ_ENUM_1(...) , __VA_ARGS__ PP_SEQ_ENUM_2
#define PP_SEQ_ENUM_2(...) , __VA_ARGS__ PP_SEQ_ENUM_1
#define PP_SEQ_ENUM_0_END
#define PP_SEQ_ENUM_1_END
#define PP_SEQ_ENUM_2_END
And define you class, something like this:
struct Derived
: PP_SEQ_ENUM(TRANSFORM(SEQ))
{
...
};
Of course, the only disadvantage with using sequence iteration, is that you can't pass a data parameter to it.
Thanks,
Paul