C ++ Macro to create an array of strings

Is there any way to create an array std::string (or char* ) with a preprocessor macro?

Something like that:

 std::string myStrings[] = {MAGIC_MACRO(a, b, c)}; 

Result:

 std::string myStrings[] = {"a", "b", "c"} 

I know this looks pointless, but I need it in a more complex macro that has a variable number of arguments

+5
source share
4 answers

The code below works on what you requested with up to 1024 arguments and without , using additional stuff like boost. It defines the EVAL(...) macro, as well as the MAP(m, first, ...) macro, to perform recursion, and use the m macro for each iteration with the following first parameter.

Using this, MAGIC_MACRO(...) looks like this: #define MAGIC_MACRO(...) EVAL(MAP(STRINGIZE, __VA_ARGS__)) .

It is mainly copied from C Pre-Processor Magic . It is also well explained. You can also download these helper macros, such as EVAL(...) in this git repository , there are many explanations in the actual code. It is variable, so the number of arguments you want is required.

But I changed the macro first and SECOND , because it uses the Gnu extension, as in the original, from which I copied it.

The main part of the function:

 int main() { std::string myStrings[] = { MAGIC_MACRO(a, b, c) }; // Expands to: std::string myStrings[] = { "a" , "b" , "c" }; std::string myStrings[] = { MAGIC_MACRO(a, b, c, x, y, z) }; // Expands to: std::string myStrings[] = { "a" , "b" , "c", "x" , "y" , "z" }; } 

Macro Definitions:

 #define FIRST_(a, ...) a #define SECOND_(a, b, ...) b #define FIRST(...) FIRST_(__VA_ARGS__,) #define SECOND(...) SECOND_(__VA_ARGS__,) #define EMPTY() #define EVAL(...) EVAL1024(__VA_ARGS__) #define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__)) #define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__)) #define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__)) #define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__)) #define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__)) #define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__)) #define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__)) #define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__)) #define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__)) #define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__)) #define EVAL1(...) __VA_ARGS__ #define DEFER1(m) m EMPTY() #define DEFER2(m) m EMPTY EMPTY()() #define IS_PROBE(...) SECOND(__VA_ARGS__, 0) #define PROBE() ~, 1 #define CAT(a,b) a ## b #define NOT(x) IS_PROBE(CAT(_NOT_, x)) #define _NOT_0 PROBE() #define BOOL(x) NOT(NOT(x)) #define IF_ELSE(condition) _IF_ELSE(BOOL(condition)) #define _IF_ELSE(condition) CAT(_IF_, condition) #define _IF_1(...) __VA_ARGS__ _IF_1_ELSE #define _IF_0(...) _IF_0_ELSE #define _IF_1_ELSE(...) #define _IF_0_ELSE(...) __VA_ARGS__ #define COMMA , #define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)()) #define _END_OF_ARGUMENTS_() 0 #define MAP(m, first, ...) \ m(first) \ IF_ELSE(HAS_ARGS(__VA_ARGS__))( \ COMMA DEFER2(_MAP)()(m, __VA_ARGS__) \ )( \ /* Do nothing, just terminate */ \ ) #define _MAP() MAP #define STRINGIZE(x) #x #define MAGIC_MACRO(...) EVAL(MAP(STRINGIZE, __VA_ARGS__)) 
+4
source

There may be a more efficient way, but you can just use Boost.PP:

 #define MAGIC_MACRO_ELEM(r, data, i, elem) \ BOOST_PP_COMMA_IF(i) BOOST_PP_STRINGIZE(elem) #define MAGIC_MACRO(...) \ BOOST_PP_SEQ_FOR_EACH_I(MAGIC_MACRO_ELEM, ~, BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))) 

Look at the living at Coliru

+3
source

A simple solution is to have a separate macro for each different account. Using a two-level "strict" macro (more on this here ), you can do something like this:

 #include <iostream> #include <sstream> #define XSTRINGIFY(s) #s #define STRINGARRAY1(s0) { XSTRINGIFY(s0) } #define STRINGARRAY2(s0, s1) { XSTRINGIFY(s0), XSTRINGIFY(s1) } #define STRINGARRAY3(s0, s1, s2) { XSTRINGIFY(s0), XSTRINGIFY(s1), XSTRINGIFY(s2) } using namespace std; string dumpStrings(string *array, int count) { stringstream ss; if (count > 0) { ss << '"' << array[0] << '"'; for(int i = 1; i < count; ++i) { ss << ", \"" << array[i]<< '"'; } } return ss.str(); } int main() { string strings1[1] = STRINGARRAY1(a); string strings2[2] = STRINGARRAY2(a, b); string strings3[3] = STRINGARRAY3(a, b, c); cout << "strings1: " << dumpStrings(strings1, sizeof(strings1) / sizeof(strings1[0])) << endl; cout << "strings2: " << dumpStrings(strings2, sizeof(strings2) / sizeof(strings2[0])) << endl; cout << "strings3: " << dumpStrings(strings3, sizeof(strings3) / sizeof(strings3[0])) << endl; } 

Output:

 strings1: "a" strings2: "a", "b" strings3: "a", "b", "c" 

If you only need one macro that takes a variable number of arguments, it gets a little dirty, as shown in other answers.

+2
source

I'm not sure if this matches what you are trying to achieve, but I usually use this technique to create strings (or other lists generated from strings, such as enumeration elements).

eg.

 #define FOREACH_APPLY(GENERATE) \ GENERATE(a) \ GENERATE(b) \ GENERATE(c) #define GENERATE_STRING(STRING) #STRING, std::string myStrings[] = { FOREACH_APPLY(GENERATE_STRING) }; 
0
source

Source: https://habr.com/ru/post/1268432/


All Articles