Podemos ter macros recursivas?

Eu quero saber se podemos ter macros recursivas em C / C ++? Se sim, forneça um exemplo de exemplo.

Segunda coisa: por que não consigo executar o código abaixo? Qual é o erro que estou cometendo? É por causa de macros recursivas?

# define pr(n) ((n==1)? 1 : pr(n-1)) void main () { int a=5; cout<<"result: "<< pr(5) <<endl; getch(); } 

    Seu compilador provavelmente fornece uma opção para apenas pré-processar, na verdade, não compilar. Isso é útil se você estiver tentando encontrar um problema em uma macro. Por exemplo, usando g++ -E :

     > g++ -E recursiveMacro.c # 1 "recursiveMacro.c" # 1 "" # 1 "" # 1 "recursiveMacro.c" void main () { int a=5; cout< <"result: "<< ((5==1)? 1 : pr(5 -1)) < 

    Como você pode ver, não é recursivo. pr(x) só é substituído uma vez durante o pré-processamento. O importante a lembrar é que todo o pré-processador substitui cegamente uma cadeia de texto por outra; na verdade, ela não avalia expressões como (x == 1) .

    A razão pela qual seu código não irá compilar é que pr(5 -1) não foi substituído pelo pré-processador, então ele acaba na fonte como uma chamada para uma function indefinida.

    As macros não se expandem diretamente recursivamente, mas existem soluções alternativas. Quando o pré-processador digitaliza e expande pr(5) :

     pr(5) ^ 

    cria um contexto de desativação, de modo que, quando ele for pr novamente:

     ((5==1)? 1 : pr(5-1)) ^ 

    ela fica pintada de azul e não pode mais se expandir, não importa o que tentemos. Mas podemos evitar que a nossa macro seja pintada de azul usando expressões adiadas e alguma indirecção:

     # define EMPTY(...) # define DEFER(...) __VA_ARGS__ EMPTY() # define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)() # define EXPAND(...) __VA_ARGS__ # define pr_id() pr # define pr(n) ((n==1)? 1 : DEFER(pr_id)()(n-1)) 

    Então agora vai se expandir assim:

     pr(5) // Expands to ((5==1)? 1 : pr_id ()(5 -1)) 

    O que é perfeito, porque o pr nunca foi pintado de azul. Nós só precisamos aplicar outra verificação para expandir ainda mais:

     EXPAND(pr(5)) // Expands to ((5==1)? 1 : ((5 -1==1)? 1 : pr_id ()(5 -1 -1))) 

    Podemos aplicar duas digitalizações para expandir ainda mais:

     EXPAND(EXPAND(pr(5))) // Expands to ((5==1)? 1 : ((5 -1==1)? 1 : ((5 -1 -1==1)? 1 : pr_id ()(5 -1 -1 -1)))) 

    No entanto, como não há nenhuma condição de finalização, nunca podemos aplicar varreduras suficientes. Não tenho certeza do que você deseja realizar, mas se você está curioso sobre como criar macros recursivas, aqui está um exemplo de como criar uma macro de repetição recursiva.

    Primeiro, uma macro para aplicar muitas digitalizações:

     #define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__))) #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__))) #define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__))) #define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__))) #define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__))) #define EVAL5(...) __VA_ARGS__ 

    Em seguida, uma macro de concatenação que é útil para correspondência de padrões:

     #define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) #define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ 

    Contadores de incremento e decremento:

     #define INC(x) PRIMITIVE_CAT(INC_, x) #define INC_0 1 #define INC_1 2 #define INC_2 3 #define INC_3 4 #define INC_4 5 #define INC_5 6 #define INC_6 7 #define INC_7 8 #define INC_8 9 #define INC_9 9 #define DEC(x) PRIMITIVE_CAT(DEC_, x) #define DEC_0 0 #define DEC_1 0 #define DEC_2 1 #define DEC_3 2 #define DEC_4 3 #define DEC_5 4 #define DEC_6 5 #define DEC_7 6 #define DEC_8 7 #define DEC_9 8 

    Algumas macros úteis para condicionais:

     #define CHECK_N(x, n, ...) n #define CHECK(...) CHECK_N(__VA_ARGS__, 0,) #define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x)) #define NOT_0 ~, 1, #define COMPL(b) PRIMITIVE_CAT(COMPL_, b) #define COMPL_0 1 #define COMPL_1 0 #define BOOL(x) COMPL(NOT(x)) #define IIF(c) PRIMITIVE_CAT(IIF_, c) #define IIF_0(t, ...) __VA_ARGS__ #define IIF_1(t, ...) t #define IF(c) IIF(BOOL(c)) #define EAT(...) #define EXPAND(...) __VA_ARGS__ #define WHEN(c) IF(c)(EXPAND, EAT) 

    Juntando tudo, podemos criar uma macro de repetição:

     #define REPEAT(count, macro, ...) \ WHEN(count) \ ( \ OBSTRUCT(REPEAT_INDIRECT) () \ ( \ DEC(count), macro, __VA_ARGS__ \ ) \ OBSTRUCT(macro) \ ( \ DEC(count), __VA_ARGS__ \ ) \ ) #define REPEAT_INDIRECT() REPEAT //An example of using this macro #define M(i, _) i EVAL(REPEAT(8, M, ~)) // 0 1 2 3 4 5 6 7 

    Então, sim com algumas soluções alternativas, você pode ter macros recursivas em C / C ++.

    Você não deveria ter macros recursivas em C ou C ++.

    A linguagem relevante do padrão C ++, seção 16.3.4, parágrafo 2:

    Se o nome da macro que está sendo substituída for encontrado durante essa varredura da lista de substituição (não incluindo o restante dos tokens de pré-processamento do arquivo de origem), ela não será substituída. Além disso, se qualquer substituição aninhada encontrar o nome da macro a ser substituída, ela não será substituída. Esses tokens de pré-processamento de nomes de macro não substituídos não estão mais disponíveis para substituição posterior, mesmo se forem posteriormente (re) examinados em contextos nos quais o token de pré-processamento desse nome de macro teria sido substituído.

    Há algum espaço de manobra neste idioma. Com várias macros que invocam uma à outra, há uma área cinza em que essas palavras não dizem exatamente o que deve ser feito. Há um problema ativo contra o padrão C ++ em relação a esse problema de advogado de linguagem; veja http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268 .

    Ignorando esse problema de advogado de idioma, cada fornecedor de compilador compreende a intenção:

    Macros recursivas não são permitidas em C ou C ++.

    O mais provável é que você não consiga executá-lo porque não pode compilá-lo. Além disso, se compilar corretamente, sempre retornaria 1. Você quis dizer (n==1)? 1 : n * pr(n-1) (n==1)? 1 : n * pr(n-1) .

    Macros não podem ser recursivas. De acordo com o capítulo 16.3.4.2 (obrigado Loki Astari), se a macro atual for encontrada na lista de substituição, ela será deixada como está, portanto, seu pr na definição não será alterado:

    Se o nome da macro que está sendo substituída for encontrado durante a verificação da lista de substituição (não incluindo o restante dos tokens de pré-processamento do arquivo de origem), ela não será substituída. Além disso, se qualquer substituição aninhada encontrar o nome da macro a ser substituída, ela não será substituída. Esses tokens de pré-processamento de nomes de macro não substituídos não estão mais disponíveis para substituição posterior, mesmo se forem posteriormente (re) examinados em contextos nos quais o token de pré-processamento desse nome de macro teria sido substituído.

    Sua chamada:

     cout< <"result: "<< pr(5) < 

    foi convertido pelo pré-processador em:

     cout< <"result: "<< (5==1)? 1 : pr(5-1) < 

    Durante isso, a definição de macro pr é 'perdida' e o compilador mostra um erro como "'pr' não foi declarado neste escopo (fato)" porque não há nenhuma function nomeada pr .

    O uso de macros não é incentivado em C ++. Por que você não escreve apenas uma function?

    Nesse caso, você poderia até mesmo escrever uma function de template para que ela fosse resolvida em tempo de compilation e se comportasse como um valor constante:

     template  int pr() { pr(); } template <> int pr<1>() { return 1; } 

    Você não pode ter macros recursivas em C ou C ++.