2011-05-31 9 views
13

estoy generando programación montón de palabras funcionales, con el fin de mantener el código generado más legible que estoy tratando de llegar a una macro que se ampliará la línea siguiente,iteración variadic argumentos de la macro

SET_STATE(FunctorA,a,b); 

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

Básicamente Será expandir al primer constructor de argumentos. La parte variable es la cantidad de argumentos para el constructor. si es posible hacer un bucle dentro de la macro y generar este código durante el preprocesamiento, aunque no tiene sentido para este caso en particular, pero tengo algunos funtores que tienen 20 o más variables a las que tienen acceso, limpiarán mucho mi código generado.

Todos los argumentos serán del mismo tipo, solo los nombres serán diferentes.

+0

No sé la respuesta a su pregunta, pero ¿ha considerado algo así como 'clase FunctorA {public: struct FunctorAParams {ref A; ref B; ...}; FunctorA (const FunctorAParams y params): params (params) {} private: const Parámetros de FunctorAParams; }; '. –

+0

Hay [Boost.Preprocessor] (http://www.boost.org/doc/libs/1_46_1/libs/preprocessor/doc/index.html), pero no puedo escribir esto hasta OTOH. :) – Xeo

+0

es el "ref a; ref b; sobre la parte de la declaración de subrutina de la salida de macro? – Wiz

Respuesta

6

Utilizando el trucado encontrado en este enlace http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/ para contar el número de argumentos y usar una macro realmente fea, puedo generar la salida que desea.

he comprobado usando gcc (test.cpp gcc -E) y funciona, No es portátil.

Código:

#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; 

Así lo siguiente:

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

producirá:

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

Nota: se puede seguir el número de argumentos siguiendo el patrón obvio.

+0

¿qué parte no es portable? –

+0

'__VA_ARGS__' es una extensión C99 y, como tal, podría o no implementarse en un preprocesador de compiladores C++ – Xeo

+0

@Hamza Yerlikaya Actualicé mi código para que el número de argumentos no sea necesario, utilizando algún truco del enlace (en mi respuesta). – Wiz

15

si se permite que boost::preprocessor y SEQ representación ((a)(b)...), probablemente el siguiente código se reunirán con el propósito:

#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)) 

El código anterior se amplía a

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

en mi entorno.

+0

No será mucho más claro y más pequeño que esto, +1. – Xeo

+0

@Xeo: ¡Gracias! :-) Posiblemente, la dependencia del boost podría ser pesada para OP aunque ... –

+0

Boost puede estar acoplado débilmente. Por ejemplo, dudo que la biblioteca Boost.Preprocessor dependa demasiado, por lo que definitivamente debería ser posible extraer los archivos necesarios si fuera necesario. –

Cuestiones relacionadas