es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo expandir una macro recursiva a través de __VA_OPT__ en un contexto anidado

He leído este artículo, el cual ilustra cómo la función macro __VA_OPT__ puede ser utilizada para expandir de forma recursiva una macro. Me gustaría implementar algo similar, pero con la diferencia de que la macro se expande en un contexto anidado.

La entrada:
cpp
NEST_RECURSIVE(A, B, C)

debería producir (el orden no importa):
cpp
((( | C) | B) | A)

Mi enfoque es ligeramente generalizado a partir del artículo:
“`cpp

<h1>define PARENS ()</h1>

<h1>define EXPAND(…) EXPAND4(EXPAND4(EXPAND4(EXPAND4(<strong>VA_ARGS</strong>))))</h1>

<h1>define EXPAND4(…) EXPAND3(EXPAND3(EXPAND3(EXPAND3(<strong>VA_ARGS</strong>))))</h1>

<h1>define EXPAND3(…) EXPAND2(EXPAND2(EXPAND2(EXPAND2(<strong>VA_ARGS</strong>))))</h1>

<h1>define EXPAND2(…) EXPAND1(EXPAND1(EXPAND1(EXPAND1(<strong>VA_ARGS</strong>))))</h1>

<h1>define EXPAND1(…) <strong>VA_ARGS</strong></h1>

<h1>define FOR<em>EACH</em>R(func, …) <strong>VA<em>OPT</em></strong>(EXPAND(FOREACH<em>HELPER</em>R(func, <strong>VA_ARGS</strong>)))</h1>

<h1>define FOR<em>EACH</em>HELPER<em>R(func, sub, …) func(<strong>VA</strong></em>OPT(FOR<em>EACH</em>AGAIN<em>R PARENS (func, <strong>VA</strong></em>ARGS)), sub)</h1>

<h1>define FOR<em>EACH</em>AGAIN<em>R() FOR</em>EACH<em>HELPER</em>R</h1>

<h1>define MY_FUNC(nested, var) (nested | var)</h1>

<h1>define NEST<em>RECURSIVE(…) FOR</em>EACH<em>R(MY</em>FUNC, <strong>VA_ARGS</strong>)</h1>

“`

El código actual produce la siguiente salida:
cpp
(FOR_EACH_HELPER_R (MY_FUNC, B, C) | A)

Como se puede ver, la expansión no ocurre más allá del primer nivel.

Imagino que tendría que utilizar EXPAND en algún otro lugar, sin embargo, no puedo averiguar dónde.

Es completamente posible que lo que estoy intentando hacer sea imposible, sin embargo, el método de expansión recursiva de macro pre-C++20 (utilizando PP_NARG) funciona con anidamiento, así que espero que el nuevo y más limpio enfoque también funcione con él.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Después de analizar tu código, he encontrado que tu macro FOR_EACH_R no está aplicando el mismo enfoque recursivo utilizado en el artículo que leíste, lo cual causa que no se expanda más allá del primer nivel.

    Para solucionar esto, necesitas modificar tu macro FOR_EACH_R para aplicar el enfoque recursivo como se muestra en el artículo. La implementación actualizada es la siguiente:

    #define FOR_EACH_R(func, ...) __VA_OPT__(FOR_EACH_HELPER_R(func, EXPAND(__VA_ARGS__)))
    #define FOR_EACH_HELPER_R(func, ...) FOR_EACH_HELPER_R1(func, __VA_ARGS__)
    #define FOR_EACH_HELPER_R1(func, sub, ...) func(__VA_ARGS__) FOR_EACH_HELPER_R2(func, sub)
    #define FOR_EACH_HELPER_R2(func, sub, ...) __VA_OPT__(FOR_EACH_HELPER_R1(func, sub, __VA_ARGS__))
    

    Esto modifica la macro FOR_EACH_R para primero EXPANDIR los argumentos de entrada, y luego aplicar un enfoque de expansión recursiva de dos pasos: FOR_EACH_HELPER_R1 aplica la lógica recursiva para el nivel actual, mientras que FOR_EACH_HELPER_R2 verifica si hay más niveles para expandir y continúa la recursión en caso afirmativo.

    Con este cambio, tu macro NEST_RECURSIVE producirá la salida deseada:

    ((( | C) | B) | A)
    

    ¡Espero que esto te ayude! Avísame si tienes alguna pregunta adicional.

Comments are closed.