Reputation: 863
I'm confident that you can use BOOST_PP_SEQ_ELEM(BOOST_PP_ADD(n,1),sequence)
, but I can't quite seem to pinpoint why the EXTRACT
macro below is unable to compile with "too few arguments provided to function like macro".
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/arithmetic/mod.hpp>
#include <boost/preprocessor/logical/not.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>
#include <iostream>
// attempt 2.7 beta
#define EXTRACT(z, n, args) \
BOOST_PP_IIF(\
/* on every third index */ \
BOOST_PP_NOT(BOOST_PP_MOD(n,3)),\
/* check the flag */ \
BOOST_PP_IIF(BOOST_PP_SEQ_ELEM(n,args),\
/*BOOST_PP_SEQ_ELEM(n,args),*/ \
BOOST_PP_SEQ_ELEM(BOOST_PP_ADD(n,1),args),\
"narp"\
),\
)
// absurd wrapper for extract
#define ALL_ARGS(args) BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(args),EXTRACT,args)
// every third element is a "flag"
// v v
#define MY_SEQUENCE (1)(int)(z)(0)(float)(y)
int main(int argc, const char **argv) {
std::cout <<
BOOST_PP_STRINGIZE(ALL_ARGS(MY_SEQUENCE))
<< std::endl;
}
The example is far from what I want to do with this, but right now I'm just trying to figure out how to get the actual int
and z
or float
and y
.
If it matters, the actual goal is instantiating templates. I have a sequence of template classes, but am unable to figure out how to instantiate
// vvvvvvvvvvvv
template <class X> void foo(SomeThing<X> varName);
So the flag here is letting me know if SomeThing
needs <X>
or not. Perhaps there is an easier way to approach this? I'm already inside a BOOST_PP_SEQ_FOR_EACH
for the classes in the template, so the only thing I could figure out how to do was pass this ugly arguments sequence along. FWIW I know int<X>
isn't valid, this is just testing...
Upvotes: 2
Views: 668
Reputation: 2674
In general preprocessor macros are easier to debug using the preprocessor than they are "tiny programs". For example, what you have here requires a full compilation and launching to see an issue; but if you comment out #include <iostream>
and #include <boost/preprocessor/stringize.hpp>
, and replace the entire main function with just ALL_ARGS(MY_SEQUENCE)
, then you can simply launch your preprocessor and see its output directly; no compilation/running necessary.
Not only is this quicker, but you get to play on a token level to produce things that can help you, without having to worry about producing things that will compile.
Using the transformation above I performed a single expansion of ALL_ARGS
(after reproducing the problem) by changing the argument EXTRACT
to EXTRACT_
. This iterated just fine. Next I changed ALL_ARGS
to the output of the expansion, breaking each EXTRACT_
on separate lines and adding an artificial label, then changed EXTRACT_
back to EXTRACT
; e.g.:
0_ EXTRACT(2, 0, (1)(int)(z)(0)(float)(y))
1_ EXTRACT(2, 1, (1)(int)(z)(0)(float)(y))
...
Running this through the preprocessor again showed that all expansions were fine, except for the sixth one:
5_ EXTRACT(2, 5, (1)(int)(z)(0)(float)(y))
This in mind it was easy to spot. The problem is indeed with this part:
BOOST_PP_SEQ_ELEM(BOOST_PP_ADD(n,1),args)
...when EXTRACT
is run with n=5, this amounts to BOOST_PP_SEQ_ELEM(6, (1)(int)(z)(0)(float)(y))
. There's no element offset 6 here, so the macro crumbles. Mind you, BOOST_PP_NOT(BOOST_PP_MOD(5,3))
is 0
, so the outer BOOST_PP_IIF
doesn't select the inner one, but it still must evaluate it.
Perhaps there is an easier way to approach this?
Absolutely. Use a different data structure. Here, your strategy is to use a sequence of size 3*n for some n, then pick out every 3 items in the sequence.
With some fiddling you can surely do this, but the entire reason you need to is because you don't really have a series of items... rather, you have a series of sets of 3 items. If you change your data structure to a sequence of 3-tuples, this becomes much much easier; all you need is an IIF
, a FOR_EACH
, and a couple of worker macros:
#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#define MY_SEQUENCE ((1,int,z))((0,float,y))
#define APPLY_EXTRACT(r,data,elem) EXTRACT elem
#define EXTRACT(FLAG_,TYPE_,PNAME_) BOOST_PP_IIF(FLAG_, TYPE_, "narp")
#define ALL_ARGS(args) BOOST_PP_SEQ_FOR_EACH(APPLY_EXTRACT, _, MY_SEQUENCE)
ALL_ARGS(MY_SEQUENCE)
Upvotes: 2