2011-01-05 8 views
9

Me parece que vi algo raro que se hace en una biblioteca de impulso y terminó siendo exactamente lo que estoy tratando de hacer ahora. No puede encontrarlo aunque ...Eliminar una lista de parámetros de f (lista) con el preprocesador

Quiero crear una macro que lleva una firma y lo convierte en una función de puntero:

void f(int,int) {} 

... 
void (*x)(int,int) = WHAT((f(int,int))); 

x(2,4); // calls f() 

especial me necesitará para trabajar con punteros de función miembro de modo que lo que tiene dos parametros:

WHAT(ClassType, (f(int,int)); // results in static_cast<void (ClassType::*)(int,int)>(&ClassType::f) 

no es absolutamente necesario con el fin de resolver mi problema, pero sería hacer las cosas un tacto más agradable.


Esta pregunta no tiene nada, per-se, que ver con los punteros de función. Lo que hay que hacer es usar el preprocesador para tomar "f (int, int)" y convertirla en dos partes diferentes:

'f' '(int, int)'


por qué:

he resuelto el problema crió aquí: Generating Qt Q_OBJECT classes pragmatically

he comenzado una serie de artículos que explican cómo hacerlo: http://crazyeddiecpp.blogspot.com/2011/01/quest-for-sane-signals-in-qt-step-1.html http://crazyeddiecpp.blogspot.com/2011/01/quest-for-sane-signals-in-qt-step-2.html

La firma debe evaluarse y coincidir exactamente con la "señal" con la que el usuario intenta conectarse. Los usuarios de Qt están acostumbrados a expresar esto como SIGNAL(fun(param,param)), por lo que algo como connect_static(SIGINFO(object,fun(param,param)), [](int,int){}) no sería demasiado extraño.

Para construir la firma, necesito poder sacarla de los argumentos proporcionados. Hay suficiente información para obtener la dirección de función del miembro (utilizando decltype de C++ 0x) y buscar la firma para generar el contenedor apropiado, pero no puedo ver cómo sacarlo. Lo más cercano que se me ocurre es SIGINFO(object, fun, (param,param)), que probablemente sea lo suficientemente bueno, pero pensé que lo haría antes de considerar imposible obtener la sintaxis exacta que prefiero.

+2

Hmm, Originalmente no entendí ... Así que explícitamente tiene que ser el argumento "(f (int, int))" - ¿se están generando de alguna manera? – villintehaspam

+0

Buena pregunta, una vez también tuve un requisito similar. Esperando respuesta. –

+0

Puede resolver este problema con 'boost :: function_traits' y' boost :: function_types :: parameter_types', pero no estoy seguro de si cumple con la estipulación del preprocesador. –

Respuesta

1

Lo que intenta hacer es imposible con el preprocesador estándar, desafortunadamente. Hay un par de razones:

  • Es imposible dividir los parámetros pasados ​​a una macro con un carácter personalizado. Deben estar delimitados por comas. De lo contrario, eso podría resolver tu problema al instante.
  • No puede usar el preprocesador para definir algo que no sea un identificador. De lo contrario, podría usar la doble expansión donde ( y ) se define como , y dividir los argumentos como si se pasara como f, int, int,, luego procesarlo como argumentos varódicos.
  • La definición del puntero de función en C++ no le permite deducir el nombre dado al tipo definido, desafortunadamente.

Yendo más lejos, incluso si logras crear un puntero de función, el código no funcionará para los métodos, porque a fin de invocar un método, es necesario tener dos punteros - puntero al método y al instancia de clase.Esto significa que tienes que tener un envoltorio alrededor de esto.

Es por eso que QT está utilizando sus propias herramientas como moc para generar código de pegamento.

Lo más importante que puede haber visto en Boost es probablemente las bibliotecas Signals, Bind y Lambda. Es irónico que esas bibliotecas sean mucho más poderosas de lo que estás tratando de lograr, pero al mismo tiempo no te permitirán lograrlo de la manera que lo desees. Por ejemplo, incluso si pudiera hacer lo que desea con la sintaxis que desea, no podrá "conectar" una ranura a una "señal" si la señal tiene una firma diferente. Al mismo tiempo, las bibliotecas de Boost I mencionadas anteriormente lo permiten totalmente. Por ejemplo, si su "ranura" espera más parámetros de los que proporciona "señal", puede vincular otros objetos para que se pasen cuando se invoca "ranura". Esas bibliotecas también pueden suprimir parámetros adicionales si "slot" no las espera.

Yo diría que la mejor forma de prospecto de C++ en la actualidad es utilizar el enfoque de Boost Signal para implementar el manejo de eventos en las bibliotecas de GUI. QT no lo usa por una serie de razones. Primero, comenzó en 90 segundos cuando C++ no era tan elegante. Además, tienen que analizar su código para trabajar con "slots" y "señales" en el diseñador gráfico.

Parece para mí que en lugar de usar macros o peor aún - herramientas no estándar en la parte superior de C++ para generar el código, y utilizando la siguiente:

void (*x)(int,int) = WHAT((f(int,int))); 

Sería mucho mejor que hacer algo como esto:

void f (int x, int y, int z); 
boost::function<void (int, int)> x = boost::bind (&f, _1, _2, 3); 
x (1, 2); 

Above funcionará tanto para funciones como para métodos.

+0

... ¿y un infractor cree que ...? –

Cuestiones relacionadas