Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate over two Boost Preprocessor sequences at the same time?

I was wondering if the following can be done via Boost Preprocessor sequences. (Most of the SO questions as well as Boost Preprocessor examples talk about only 1 sequence)

#define seq1 (a)(b)(c)
#define seq2 (1)(2)(3)

// Now iterate over both of them at the same time

Here is my motivation. I have to define few functions for a lot of types e.g.

void add(int val) { obj.AddInt(val); }
void add(double val) { obj.AddDouble(val); }

I was thinking of defining two sequences like

#define types (int)(double)...
#define funcs (AddInt)(AddDouble)...

and then write a macro for the function add, and iterate over the two sequences.

like image 526
skgbanga Avatar asked Feb 01 '17 14:02

skgbanga


1 Answers

You could use BOOST_PP_SEQ_FOR_EACH_I and BOOST_PP_SEQ_ELEM to do it as follows:

#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>

#define types (int)(double)
#define funcs (AddInt)(AddDouble)

#define MACRO(_,funcs,i,type) \
    void add(type val) { obj.BOOST_PP_SEQ_ELEM(i, funcs)(val); }

BOOST_PP_SEQ_FOR_EACH_I(MACRO, funcs, types)

The BOOST_PP_SEQ_FOR_EACH_I macro iterates over the sequence types, applying MACRO to each element. The second argument to BOOST_PP_SEQ_FOR_EACH_I is passed as the second argument to each invocation of MACRO, and i denotes the zero-based index of the current element being iterated over. Therefore, when MACRO is being expanded, type is the i-th element of types and BOOST_PP_SEQ_ELEM(i, funcs) is the i-th element of funcs.

For a more general solution, you can do something like:

#define ITERATE_OVER_TWO_SEQ_(_,data,i,e2) \
   BOOST_PP_SEQ_ELEM(0,data)(BOOST_PP_SEQ_ELEM(i, BOOST_PP_SEQ_ELEM(1,data)), e2)
#define ITERATE_OVER_TWO_SEQ(macro, s1, s2) \
    BOOST_PP_SEQ_FOR_EACH_I(ITERATE_OVER_TWO_SEQ_, (macro)(s1), s2)

and use it as follows:

#define MACRO(type,func) void add(type val) { obj.func(val); }
ITERATE_OVER_TWO_SEQ(MACRO, types, funcs)

An even more generic way would be to use SEQ_ZIP from this answer, BOOST_PP_SEQ_FOR_EACH and BOOST_PP_SEQ_ELEM. For example:

#include <boost/preprocessor/seq/for_each.hpp>
#define MACRO(_,d,seq) \
    void add(BOOST_PP_SEQ_ELEM(0,seq) val) \
    { obj.BOOST_PP_SEQ_ELEM(1, seq)(val); }

BOOST_PP_SEQ_FOR_EACH(MACRO, _, SEQ_ZIP((types)(funcs))
like image 129
jotik Avatar answered Oct 21 '22 03:10

jotik