Search code examples
c++boostpreprocessor

Preprocessor initialize array


How, if necessary, using boost preprocessor, initialize the array as follows:

INIT_ARRAY(plus,minus)
//extract to 
std::array<std::pair<char const *,std::string>, 2> array{{
{"plus", std::string("plus")}, {"minus", std::string("minus")} }};

INIT_ARRAY(plus,minus,multiply)
//extract to 
std::array<std::pair<char const *,std::string>, 3> array{{
{"plus", std::string("plus")}, {"minus", std::string("minus")}, {"multiply", std::string("multiply")} }};

P.S. Couldn't solve the problem with the last comma in the initializer (...{n-1} , {n} ,) and counting the number of arguments to pass to std::array<...,n>. I use the preprocessor, since the names passed to the macro will be used later for code generation. Used c++20


Solution

  • You can use BOOST_PP_COMMA_IF for conditional commas, and BOOST_PP_VARIADIC_SIZE to work out the size beforehand.

    This should work (for non-empty arrays):

    #include <boost/preprocessor/punctuation/comma_if.hpp>
    #include <boost/preprocessor/seq/for_each_i.hpp>
    #include <boost/preprocessor/stringize.hpp>
    #include <boost/preprocessor/variadic/size.hpp>
    #include <boost/preprocessor/variadic/to_seq.hpp>
    
    
    #define INIT_ARRAY_INITIALIZER(r, _, i, e) BOOST_PP_COMMA_IF(i) {BOOST_PP_STRINGIZE(e), std::string(BOOST_PP_STRINGIZE(e))}
    
    #define INIT_ARRAY(...) \
    std::array<std::pair<char const *, std::string>, \
    BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)> array{{ \
        BOOST_PP_SEQ_FOR_EACH_I(INIT_ARRAY_INITIALIZER, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
    }};