Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic macro to create struct

How can I write a macro (for gcc) that would be used like this:

CREATE_STRUCT(my_struct1,foo);
CREATE_STRUCT(my_struct2,foo,bar);

and expands to

struct my_struct1 {
     std::string foo;
};

struct my_struct2 {
     std::string foo;
     std::string bar;
};

?

I certainly do need the flexibility of different number of members, but already a small number would be fine for me (something like 4 or 5).

I found a couple of related questions, eg this and this, but I am completely lost when trying to apply such arcane macro magic to this problem.

PS: I know how I could write 5 macros (one for each number of params) that would do the job, so actually the question is: Is there an "easy" way to write a variadic macro that does the job? On the other hand, I will add more stuff to the structs, so having it all in one place would save lots of boilerplate.

like image 864
463035818_is_not_a_number Avatar asked Apr 25 '18 08:04

463035818_is_not_a_number


People also ask

How do I use Variadic macros?

To use variadic macros, the ellipsis may be specified as the final formal argument in a macro definition, and the replacement identifier __VA_ARGS__ may be used in the definition to insert the extra arguments. __VA_ARGS__ is replaced by all of the arguments that match the ellipsis, including commas between them.

What is __ Va_args __ C++?

Preprocessor: __VA_ARGS__ (Variadic macros) If the parameters of a macro contain three consecutive dots ( ... ), this indicates that an arbitrary number of parameters may be passed. In the macro expansion, these values that are then referenced by the special identifier __VA_ARGS__ .

What is ## args in C?

The variable argument is completely macro-expanded before it is inserted into the macro expansion, just like an ordinary argument. You may use the ' # ' and ' ## ' operators to stringize the variable argument or to paste its leading or trailing token with another token.

Is printf a macro?

We can use printf() function in a Macro. In this example, we are creating a function like Macro that will print the result of a calculation, like adding two numbers.

What are variadic macros in C++?

Variadic macros are function-like macros that contain a variable number of arguments. To use variadic macros, the ellipsis may be specified as the final formal argument in a macro definition, and the replacement identifier __VA_ARGS__ may be used in the definition to insert the extra arguments.

How to count the number of ARGs in a variadic macro?

// Count how many args are in a variadic macro. Only works for up to N-1 args. See how it works? The first macro, _GET_NTH_ARG (), takes any number of args >= N, but always returns item N (in this case, N =5).

How many ARGs can a variadic macro take in Python?

* Provide a for-each construct for variadic macros. Supports up * to 4 args. #define CALL_MACRO_X_FOR_EACH (x, …)

How to use structures in VBA?

This tutorial will demonstrate how to use structures in VBA. A structure in VBA is essentially a user-defined data type. When we use variables in VBA, we can declare them a string variable, number variables etc. Creating a structure essentially creates a new variable type, the structure itself can contain multiple data types.


Video Answer


3 Answers

Using code from Is it possible to iterate over arguments in variadic macros? , you may do (Hard coded up to 8 arguments):

#define CONCATENATE(arg1, arg2)   CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2)  CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2)  arg1##arg2

#define FOR_EACH_1(what, x) what(x);
#define FOR_EACH_2(what, x, ...)\
  what(x);\
  FOR_EACH_1(what,  __VA_ARGS__)
#define FOR_EACH_3(what, x, ...)\
  what(x);\
  FOR_EACH_2(what, __VA_ARGS__)
#define FOR_EACH_4(what, x, ...)\
  what(x);\
  FOR_EACH_3(what,  __VA_ARGS__)
#define FOR_EACH_5(what, x, ...)\
  what(x);\
 FOR_EACH_4(what,  __VA_ARGS__)
#define FOR_EACH_6(what, x, ...)\
  what(x);\
  FOR_EACH_5(what,  __VA_ARGS__)
#define FOR_EACH_7(what, x, ...)\
  what(x);\
  FOR_EACH_6(what,  __VA_ARGS__)
#define FOR_EACH_8(what, x, ...)\
  what(x);\
  FOR_EACH_7(what,  __VA_ARGS__)

#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) FOR_EACH_ARG_N(__VA_ARGS__) 
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N 
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0

#define FOR_EACH_(N, what, ...) CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__)
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)

#define STRING_MEMBERS(x) std::string x

#define CREATE_STRUCT(name, ...) struct name { FOR_EACH(STRING_MEMBERS, __VA_ARGS__) }

CREATE_STRUCT(my_struct1, foo);
CREATE_STRUCT(my_struct2,foo,bar);
like image 73
Jarod42 Avatar answered Oct 22 '22 10:10

Jarod42


This works with any number of arguments:

#define CREATE_STRUCT(N, ...) struct N { std::string __VA_ARGS__; }

Examples:

CREATE_STRUCT(MyStruct, foo);
CREATE_STRUCT(MyStruct, foo, bar);
CREATE_STRUCT(MyStruct, foo, bar, baz);
like image 23
JustinC Avatar answered Oct 22 '22 09:10

JustinC


Here is simple implementation, limited to five members.

#define CREATE_STRUCT_IMPL_1(S1) std::string S1;
#define CREATE_STRUCT_IMPL_2(S1, ...) CREATE_STRUCT_IMPL_1(S1) CREATE_STRUCT_IMPL_1(__VA_ARGS__)
#define CREATE_STRUCT_IMPL_3(S1, ...) CREATE_STRUCT_IMPL_1(S1) CREATE_STRUCT_IMPL_2(__VA_ARGS__)
#define CREATE_STRUCT_IMPL_4(S1, ...) CREATE_STRUCT_IMPL_1(S1) CREATE_STRUCT_IMPL_3(__VA_ARGS__)
#define CREATE_STRUCT_IMPL_5(S1, ...) CREATE_STRUCT_IMPL_1(S1) CREATE_STRUCT_IMPL_4(__VA_ARGS__)

#define CREATE_STRUCT_IMPL(_1,_2,_3,_4,_5,NAME,...) NAME

#define CREATE_STRUCT(N, ...) struct N{ CREATE_STRUCT_IMPL(__VA_ARGS__, CREATE_STRUCT_IMPL_5, CREATE_STRUCT_IMPL_4, CREATE_STRUCT_IMPL_3, CREATE_STRUCT_IMPL_2, CREATE_STRUCT_IMPL_1)(__VA_ARGS__) }

Examples

CREATE_STRUCT(my_struct1, foo);
CREATE_STRUCT(my_struct2, foo, bar);
CREATE_STRUCT(my_struct3, foo, bar, meow);
CREATE_STRUCT(my_struct4, foo, bar, meow, bazz);
CREATE_STRUCT(my_struct5, foo, bar, meow, bazz, dash);
like image 22
Jonas Avatar answered Oct 22 '22 09:10

Jonas