Search code examples
c++boostmacrosboost-preprocessor

Using boost preprocessor to call a variadic template iteratively


Assume I have a variadic template:

template<typename... Args>
class Foo;

This variadic template generates another template recursively until it reaches the one argument Foo in the last level. Now I want to have a macro for example Bar(...) which when I call it I get something like this:

Bar(float, int, string, vector<int>)
// expands to
Macro(Foo<float, int, string, vector<int>>)
Macro(Foo<int, string, vector<int>>)
Macro(Foo<string, vector<int>>)
Macro(Foo<vector<int>>)

Which Macro(...) is another macro for doing something on this class. I hope to able to use Boost Preprocessor to reduce the code I have to write.

Please suggest me some tips that helps me to write such macro.


Solution

  • I don't know if this is the best approach to solving your problem but this does what you want:

    #include <boost/preprocessor/repetition/repeat_from_to.hpp>
    #include <boost/preprocessor/seq.hpp>
    #include <boost/preprocessor/variadic/to_seq.hpp>
    
    #define CALL_MACRO(_,__,SEQ) Macro(Foo<BOOST_PP_SEQ_ENUM(SEQ)>)
    
    #define GENERATE_MACRO_INVOCATIONS(SEQS) BOOST_PP_SEQ_FOR_EACH(CALL_MACRO,_,SEQS)
    
    #define GENERATE_DESCENDING_SEQUENCES(_,INDEX,DATA) (BOOST_PP_SEQ_REST_N(INDEX,DATA))
    
    #define BAR_IMPL(SEQ) GENERATE_MACRO_INVOCATIONS(BOOST_PP_REPEAT_FROM_TO(0,BOOST_PP_SEQ_SIZE(SEQ),GENERATE_DESCENDING_SEQUENCES, SEQ))
    
    
    #define Bar(...) BAR_IMPL(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
    
    Bar(float, int, string, vector<int>)
    
    • You initially have a variadic data: float, int, string, vector<int>.
    • BOOST_PP_VARIADIC_TO_SEQ transforms it to: (float)(int)(string)(vector<int>)
    • BOOST_PP_REPEAT_FROM_TO calls the macro GENERATE_DESCENDING_SEQUENCES BOOST_PP_SEQ_SIZE(SEQ) times with the sequence as data and an index that starts from 0.
    • BOOST_PP_SEQ_REST_N(INDEX,DATA) removes the INDEX first elements from DATA and returns the rest. This result is put inside a couple of parentheses.
    • After the invocation of the REPEAT you have a sequence of sequences:

      ((float)(int)(string)(vector))((int)(string)(vector))((string)(vector))((vector))

    • BOOST_PP_SEQ_FOR_EACH calls CALL_MACRO with every element in the sequence of sequences.

    • And finally BOOST_PP_SEQ_ENUM takes a sequence and returns its elements separated by commas.

    Preprocessed on Coliru