Stringify each token in __VA_ARGS__ from a variadic macro

159 Views Asked by At

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.

1

There are 1 best solutions below

4
KamilCuk On BEST ANSWER

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';
    }
}