Search code examples
c++boostc++20variadic-macrosboost-preprocessor

Stringify each token in __VA_ARGS__ from a variadic macro


I am trying to #stringify each token in a __VA_ARGS__ from a variadic macro.

The idea is to use these tokens as entries in an enum and also push them (stringified) to a std::vector<std::string>. Assuming the enum entries have default values, they would then map as indices in the vector.

Example:

#include <vector>
#include <string>

#define MAKE_ENUM_AND_STRINGS(...)\
    enum test_enum{ __VA_ARGS__ };\
    std::vector<std::string> test_vector{ /*bad*/__VA_ARGS__/*bad*/ }

void foo() {
    MAKE_ENUM_AND_STRINGS(a, b, c, d);
}

I have already read many posts about it and can't find a satisfying solution (I don't want to define 20+ macros to "parse" __VA_ARGS__) - I wonder if something new in C++20 or C++23 would make this possible ?

EDIT: I am now looking for a solution using boost/preprocessor.


Solution

  • Overload the macro on number of arguments.

    #include <vector>
    #include <string>
    #include <iostream>
    
    #define FOREACH_STRINGIFY_1(a)       #a
    #define FOREACH_STRINGIFY_2(a, ...)  #a, FOREACH_STRINGIFY_1(__VA_ARGS__)
    #define FOREACH_STRINGIFY_3(a, ...)  #a, FOREACH_STRINGIFY_2(__VA_ARGS__)
    #define FOREACH_STRINGIFY_4(a, ...)  #a, FOREACH_STRINGIFY_3(__VA_ARGS__)
    #define FOREACH_STRINGIFY_N(_4,_3,_2,_1,N,...) \
            FOREACH_STRINGIFY##N
    #define FOREACH_STRINGIFY(...)  \
            FOREACH_STRINGIFY_N(__VA_ARGS__,_4,_3,_2,_1) \
            (__VA_ARGS__)
    
    #define MAKE_ENUM_AND_STRINGS(...) \
        enum test_enum{ __VA_ARGS__ }; \
        std::vector<std::string> test_vector{ \
             FOREACH_STRINGIFY(__VA_ARGS__) \
        }
    
    int main() {
        MAKE_ENUM_AND_STRINGS(a, b, c, d);
        for (auto&& i : test_vector) {
            std::cout << i << '\n';
        }
    }
    

    I think this is an unusual way to have a way to stringify enums. I think usually X macros method is used. Consider using an existing stringifing enum library, instead of reinventing the wheel, there are so many of them, like How to convert an enum to a string in modern C++ .


    I am now looking for a solution using boost/preprocessor tho

    #include <vector>
    #include <string>
    #include <iostream>
    #include <boost/preprocessor/stringize.hpp>
    #include <boost/preprocessor/list/for_each.hpp>
    #include <boost/preprocessor/variadic/to_list.hpp>
    
    #define MAKE_ENUM_AND_STRINGS_CALLBACK(r, data, elem)  \
        BOOST_PP_STRINGIZE(elem),
    
    #define MAKE_ENUM_AND_STRINGS(...) \
        enum test_enum { __VA_ARGS__ }; \
        std::vector<std::string> test_vector{ \
            BOOST_PP_LIST_FOR_EACH( \
                MAKE_ENUM_AND_STRINGS_CALLBACK, \
                _, \
                BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__) \
            ) \
        }
    
    int main() {
        MAKE_ENUM_AND_STRINGS(a, b, c, d);
        for (auto&& i : test_vector) {
            std::cout << i << '\n';
        }
    }