web-dev-qa-db-fra.com

Existe-t-il un moyen de faire un #define à l'intérieur d'un autre #define?

Je sais que j'essaie de me tirer une balle dans la jambe;) Cependant, cela me permettra de rendre le reste (grande quantité) de code plus petit et plus lisible.

Existe-t-il un moyen délicat de créer une macro de préprocesseur à l'intérieur d'une autre macro de préprocesseur?

Voici l'exemple, ce que je recherche. Mon vrai scénario est plus complexe

// That's what I want to do and surely C++ doesn't like it.
#define MACROCREATER(B) #define MACRO##B B+B

void foo()
{
 MACROCREATOR(5) // This should create new macro (#define MACRO5 5+5)

 int a = MACRO5; // this will use new macro
}
48
Victor Ronin

La norme C++ dit (16.3.4.3):

La séquence de jetons de prétraitement complètement remplacée [...] de l'extension de macro ...] qui en résulte n'est pas traitée comme une directive de prétraitement même si elle en ressemble à une ...

Donc non, il n'y a pas de moyen "officiel" de réaliser ce que vous voulez avec des macros.

46
hkaiser

Non. Même si une macro se développe en quelque chose qui ressemble à une directive de prétraitement, l'expansion n'est pas évaluée comme une directive de prétraitement.

15
James McNellis

En complément des réponses ci-dessus, si vous vraiment vouliez prétraiter un fichier source deux fois - ce qui est presque certainement pas ce que vous voulez réellement faire - vous pourriez toujours invoquez votre compilateur comme ceci:

g++ -E input.cpp | g++ -c -x c++ - -o output.o

Autrement dit, exécutez le fichier via le préprocesseur, puis exécutez la sortie prétraitée via le canal via une routine de compilation complète, y compris une deuxième étape de prétraitement. Pour que cela ait une assez bonne chance de fonctionner, j'imagine que vous devriez être plutôt prudent dans la façon dont vous avez défini et utilisé vos macros, et dans l'ensemble, cela ne vaudrait probablement pas la peine et la construction accrue temps.

Si vous voulez vraiment des macros, utilisez des solutions standard basées sur des macros. Si vous voulez vraiment une métaprogrammation à la compilation, utilisez des modèles.

Sur une note légèrement liée, cela me rappelle le fait que le langage de raytracing POV-Ray a fait un usage intensif d'un langage de prétraitement assez complexe, avec des directives de contrôle de flux telles que #while qui permettait la répétition conditionnelle, les calculs au moment de la compilation et d'autres avantages similaires. Si tel était le cas en C++, mais ce n'est tout simplement pas le cas, nous le faisons simplement d'une autre manière.

9
Jon Purdy

Non. Le pré-processeur est à passage unique. Il ne réévalue pas les extensions de macro.

6
Laurence Gonsalves

Comme indiqué, on peut #inclure un fichier particulier plus d'une fois avec différentes définitions de macro actives. Cela peut rendre pratique l'obtention de certains effets qui ne pourraient être obtenus pratiquement par aucun autre moyen.

À titre d'exemple simple, sur de nombreux systèmes embarqués, l'indirection de pointeur est très coûteuse par rapport à l'accès variable direct. Le code qui utilise beaucoup d'indirection de pointeur peut très bien être deux fois plus volumineux et lent que le code qui utilise simplement des variables. Par conséquent, si une routine particulière est utilisée avec deux ensembles de variables, dans un scénario où l'on passe généralement un pointeur vers une structure et utilise ensuite l'opérateur flèche, il peut être beaucoup plus efficace de simplement placer la routine dans son propre fichier. (J'utilise normalement l'extension .i) qui est #inclus une fois sans macro _PASS2 définie, et une deuxième fois avec. Ce fichier peut alors #ifdef _PASS2/# else pour définir des macros pour toutes les variables qui devraient être différentes sur les deux passes. Même si le code est généré deux fois, sur certains micros, cela prendra moins de place que d'utiliser l'opérateur flèche avec des pointeurs transmis.

3
supercat

Jetez un oeil à m4. Il est similaire à cpp, mais récursif et beaucoup plus puissant. J'ai utilisé m4 pour créer un langage structuré pour les assembleurs, par exemple.

  cmp r0, #0
  if(eq)
    mov r1, #0
  else
    add r1, #1
  end

Le "si", "sinon" et "fin" sont des appels aux macros m4 que j'ai écrites qui génèrent des sauts et des étiquettes, le reste est un assemblage natif. Pour imbriquer ces constructions if/else/end, vous devez effectuer des définitions dans une macro.

3
Jonathan Engdahl