Search code examples
c++boostboost-preprocessor

Using boost preprocessor to stringize a tuple


I am beginner in using boost preprocessor. I want to use this library to generate a name from a tuple, for example I have a tuple like this (float, string, int, bool) and I want to construct something like this "Foo<float, string, int, bool>". I thought that it must be easy by using BOOST_PP_STRINGIZE, BOOST_PP_CAT and BOOST_PP_REPEAT but I unfortunately could not find a way to generate the string I wanted.

Please give me a suggestion about creating this string. Foo is a class name and tuple is generated automatically during preprocess.


Solution

  • You can use BOOST_PP_TUPLE_ENUM to get a comma-separated expansion of the tuple elements. You can then use #__VA_ARGS__ to stringize the resulting list. See it live:

    #define STRINGIZE_ALL_I(...) #__VA_ARGS__
    #define STRINGIZE_ALL(...) STRINGIZE_ALL_I(__VA_ARGS__)
    
    #define MAKE_STRING(tuple) STRINGIZE_ALL(Foo<BOOST_PP_TUPLE_ENUM(tuple)>)
    
    // "Foo<float, string, int, bool>"
    MAKE_STRING((float, string, int, bool))
    

    STRINGIZE_ALL_I exists for the same reason you have an extra layer in STRINGIZE and CONCAT - to evaluate macros before stringizing. In this case, you would get a string containing BOOST_PP_TUPLE_ENUM((…)) if you neglected to have two layers.

    Note that STRINGIZE_ALL is called with the argument list Foo<float, string, int, bool>. That's four arguments, not one.


    If variadic macros are not available (e.g., C++98), you can take advantage of the fact that "abc" "def" will be turned into "abcdef" by the compiler. See it live:

    #define STRINGIZE_ALL_MACRO(s, state, x) state "," BOOST_PP_STRINGIZE(x)
    
    #define STRINGIZE_ALL(seq)      \
        BOOST_PP_SEQ_FOLD_LEFT(     \
            STRINGIZE_ALL_MACRO,    \
            BOOST_PP_STRINGIZE(BOOST_PP_SEQ_HEAD(seq)), \
            BOOST_PP_SEQ_TAIL(seq)  \
        )
    
    #define MAKE_STRING(size, tuple) \
        STRINGIZE_ALL(               \
            BOOST_PP_TUPLE_TO_SEQ(   \
                size,                \
                (Foo<BOOST_PP_TUPLE_ENUM(size, tuple)>) \
            )                        \
        )
    
    // "Foo<float" "," "string" "," "int" "," "bool>"
    MAKE_STRING(4, (float, string, int, bool))
    

    For this version, your autogenerated tuple must generate a size as well. It's entirely possible to generate a tuple (size, (elems)) that you can use with this macro.