5

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.

jotik
  • 14,982
  • 9
  • 48
  • 106
skgbanga
  • 1,915
  • 1
  • 11
  • 20
  • Why not a single sequence of tuples? E.g. `((int, AddInt), (double, AddDouble))`... – Vittorio Romeo Feb 01 '17 at 14:56
  • I actually have 3-4 sequences and I have read this question: http://stackoverflow.com/questions/26475453/how-to-use-boostpreprocessor-to-unzip-a-sequence I guess this potentially can be done, but was wondering if there is a way for iterating over multiple sequences because those macros sequences are already defined. – skgbanga Feb 01 '17 at 15:01
  • A quick search shows me there's a library out there with a zip macro: https://github.com/mcinglis/libpp/blob/master/zip.h – chris Feb 01 '17 at 15:03

1 Answers1

5

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))
Community
  • 1
  • 1
jotik
  • 14,982
  • 9
  • 48
  • 106