Search code examples
c++cboostc-preprocessorboost-preprocessor

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.


Solution

  • 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))