svenevs
svenevs

Reputation: 863

instantiating template functions and classes with boost preprocess

Working with the seemingly standard w, x, y, z demos, suppose I have the following macro trying to be converted to an "iterable" preprocessor macro

#define INSTANTIATE_FUNC(rtype, func_name, ...)  \
    template rtype func_name< w > (__VA_ARGS__); \
    template rtype func_name< x > (__VA_ARGS__); \
    template rtype func_name< y > (__VA_ARGS__); \
    template rtype func_name< z > (__VA_ARGS__);

For completeness, suppose we're trying to instantiate the following

struct w { static constexpr int data = 0; };
struct x { static constexpr int data = 1; };
struct y { static constexpr int data = 2; };
struct z { static constexpr int data = 3; };

template <class Data>
void printData(const std::string &prefix) {
    std::cout << prefix << Data::data << std::endl;
}

INSTANTIATE_FUNC(void, printData, const std::string &prefix)

I made a minimal gist with a build system for convenience so that if you are interested in trying you don't have to recreate everything :)

I can't quite figure out how to approach this. The only functional (but not useful) stab

#include <boost/preprocessor/list/for_each.hpp>

#define LIST (w, (x, (y, (z, BOOST_PP_NIL))))
#define MACRO(r, data, elem) template void data < elem > (const std::string &prefix);

#define INSTANTIATE_FUNC(rtype, func_name, ...) \
    BOOST_PP_LIST_FOR_EACH(MACRO, func_name, LIST)

This is works, but is clearly not adequate.

  1. Why does this not also work with sequences?

    #include <boost/preprocessor/seq/for_each.hpp>
    // this does work, my code included the wrong header
    // on what I was testing with (seq/for_each_i.hpp)
    
    #define SEQ (x)(y)(z)(w)
    #define INSTANTIATE_FUNC(rtype, func_name, ...) \
        BOOST_PP_SEQ_FOR_EACH(MACRO, func_name, SEQ)
    
  2. How should I approach building template rtype func_name < {w,x,y,z} > {args,in,__VA_ARGS__}? I tried quite a few different things, but the problem seems to be not being able to e.g. only extract w and then loop through __VA_ARGS__, then continue on. I've been trying like heck to get BOOST_PP_LIST_FOR_EACH_R to work. Is this at least the right thing to look at?

  3. As a sanity check, you can't define a macro within a macro right? Something in the spirit of

    #define INSTANTIATE_FUNC(rtype, func_name, ...) \
        #define MACRO_##func_name(r, data, elem) data < elem > (__VA_ARGS__); \
        BOOST_PP_LIST_FOR_EACH(MACRO_##func_name, func_name, LIST)
    

I'm ultimately working toward the goal of enabling optional extension of LIST / SEQ (SEQ seeming much easier to achieve this for) if that means anything. Thanks for any suggestions / resources.

Upvotes: 5

Views: 389

Answers (1)

llonesmiz
llonesmiz

Reputation: 155

Your problem seems to be that you need to deliver several pieces of data to your MACRO in BOOST_PP_(LIST|SEQ)_FOR_EACH and there is only one "slot" that you can use. The thing that you seem to be missing is the fact that you can group those pieces in, for example, a tuple and then access the different elements inside your MACRO using BOOST_PP_TUPLE_ELEM. Something like this could work:

//These are not required, just to help with readability
#define MACRO_GET_RETURN_TYPE(TUPLE)  BOOST_PP_TUPLE_ELEM(3,0,TUPLE)
#define MACRO_GET_FUNC_NAME(TUPLE)  BOOST_PP_TUPLE_ELEM(3,1,TUPLE)
#define MACRO_GET_ARGS_SEQ(TUPLE)  BOOST_PP_TUPLE_ELEM(3,2,TUPLE)


#define MACRO(_, DATA, ELEM) template MACRO_GET_RETURN_TYPE(DATA) MACRO_GET_FUNC_NAME(DATA) < ELEM > (BOOST_PP_SEQ_ENUM(MACRO_GET_ARGS_SEQ(DATA)));

// with boost seq
#define SEQ (x)(y)(z)(w)

#define INSTANTIATE_FUNC(rtype, func_name, ...) \
    BOOST_PP_SEQ_FOR_EACH(MACRO, (rtype,func_name,BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)), SEQ)

Live on Wandbox

PS: No, you can't define a macro within a macro, and the code you posted here does work for sequences, the one in your gist does not due to using the wrong header.

Upvotes: 2

Related Questions