Iterating Variadic Macro Arguments

2019-01-17 08:25发布

I am programmatically generating bunch of functors, in order to keep the generated code more readable I am trying to come up with a macro that will expand line the following,

SET_STATE(FunctorA,a,b);

ref a;
ref b;
FunctorA(ref a, ref b){
   this->a = a;
   this->b = b;
}

Basically it will expand to the first arguments constructor. Variadic part is the number of arguments to the constructor. is it possible to loop inside the macro and generate this code during preprocessing even though it does not make sense for this particular case but I have some functors that have 20 or so variables that they have access to it will cleanup my generated code a lot.

All arguments will be of the same type, only names will differ.

2条回答
成全新的幸福
2楼-- · 2019-01-17 08:58

Using the tricked found in this link http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/ to count the number of arguments and using some really ugly macro I can generate the output you wanted.

I tested it using gcc (gcc -E test.cpp) and it works, It's not portable.

Code:

#define VA_NARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)
#define SET_STATEGENERATE(name, count, ...)             \
        dec ## count (__VA_ARGS__)                      \
        name(ref ## count (__VA_ARGS__)) {              \
            con ## count (__VA_ARGS__)                  \
        }
#define SET_STATEP(name, count, ...) SET_STATEGENERATE(name, count, __VA_ARGS__) 
#define SET_STATE(name, ...) SET_STATEP(name, VA_NARGS(__VA_ARGS__), __VA_ARGS__)
/* args */
#define dec1(a) ref a;
#define dec2(a,b) dec1(a) ref b;
#define dec3(a,b,c) dec2(a, b) ref c;
#define dec4(a,b,c,d) dec3(a,b,c) ref d;
#define dec5(a,b,c,d,e) dec4(a,b,c,d) ref e;
#define dec6(a,b,c,d,e,f) dec5(a,b,c,d,e) ref f;
#define dec7(a,b,c,d,e,f,g) dec6(a,b,c,d,e,f)ref g;
#define dec8(a,b,c,d,e,f,g,h) dec7(a,b,c,d,e,f,g) ref h;
#define ref1(a) ref a
#define ref2(a,b) ref1(a), ref b
#define ref3(a,b,c) ref2(a,b), ref c
#define ref4(a,b,c,d) ref3(a,b,c), ref d
#define ref5(a,b,c,d,e) ref4(a,b,c,d), ref e
#define ref6(a,b,c,d,e,f) ref5(a,b,c,d,e), ref f
#define ref7(a,b,c,d,e,f,g) ref6(a,b,c,d,e,f), ref g
#define ref8(a,b,c,d,e,f,g, h) ref7(a,b,c,d,e,f,g), ref h
#define con1(a) this->a = a;
#define con2(a,b) con1(a) this->b = b;
#define con3(a,b,c) con2(a,b) this->c = c;
#define con4(a,b,c,d) con3(a,b,c) this->d = d;
#define con5(a,b,c,d,e) con4(a,b,c,d) this->e = e;
#define con6(a,b,c,d,e,f) con5(a,b,c,d,e) this->f = f;
#define con7(a,b,c,d,e,f,g) con6(a,b,c,d,e,f) this->g = g;
#define con8(a,b,c,d,e,f,g,h) con7(a,b,c,d,e,f,g) this->h = h;

So the following:

/* 2 args */
SET_STATE(FunctorAA, foo, bar)
/* 3 args */
SET_STATE(FunctorBB, foo, bar, baz)
/* 4 args */    
SET_STATE(FunctorCC, foo, bar, baz, qux)

will produce:

ref foo; ref bar; FunctorAA(ref foo, ref bar) { this->foo = foo; this->bar = bar; }
ref foo; ref bar; ref baz; FunctorBB(ref foo, ref bar, ref baz) { this->foo = foo; this->bar = bar; this->baz = baz; }
ref foo; ref bar; ref baz; ref qux; FunctorCC(ref foo, ref bar, ref baz, ref qux) { this->foo = foo; this->bar = bar; this->baz = baz; this->qux = qux; }

Note: you can continue the number of arguments following the obvious pattern.

查看更多
爷的心禁止访问
3楼-- · 2019-01-17 08:58

If boost::preprocessor and SEQ representation((a)(b)...) are allowed, probably the following code will meet the purpose:

#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>

#define DEF_MEMBER( r, data, elem ) ref elem;
#define DEF_PARAM( r, data, i, elem ) BOOST_PP_COMMA_IF( i ) ref elem
#define DEF_ASSIGN( r, data, elem ) this->elem = elem;

#define SET_STATE( f, members )                         \
  BOOST_PP_SEQ_FOR_EACH( DEF_MEMBER,, members )         \
  f( BOOST_PP_SEQ_FOR_EACH_I( DEF_PARAM,, members ) ) { \
      BOOST_PP_SEQ_FOR_EACH( DEF_ASSIGN,, members )     \
  }

SET_STATE(FunctorA,(a)(b))

The above code is expanded to

ref a; ref b; FunctorA( ref a , ref b ) { this->a = a; this->b = b; }

in my environment.

查看更多
登录 后发表回答