Replacing text macros
Le préprocesseur prend en charge le remplacement de macros textuelles. Le remplacement de macros textuelles de type fonction est également pris en charge.
SommaireSyntaxe
Explication
#define directivesLes directives #define définissent l' identifier comme macro, c'est-à-dire qu'elles indiquent au compilateur de remplacer la plupart des occurrences successives de l' identifier par la replacement-list , qui sera traitée ultérieurement. Des exceptions surviennent selon les règles de balayage et remplacement . Si l'identifiant est déjà défini comme un quelconque type de macro, le programme est mal formé sauf si les définitions sont identiques. Macros de type objetLes macros de type objet remplacent chaque occurrence de l' identifiant défini par la liste-de-remplacement . La version (1) de la directive #define se comporte exactement de cette manière. Macros de type fonctionLes macros de type fonction remplacent chaque occurrence de l' identifiant défini par la liste-de-remplacement , en prenant en plus un certain nombre d'arguments qui remplacent ensuite les occurrences correspondantes de l'un des paramètres dans la liste-de-remplacement . La syntaxe d'un appel de macro de type fonction est similaire à la syntaxe d'un appel de fonction : chaque occurrence du nom de la macro suivie d'un ( comme prochain jeton de préprocesseur introduit la séquence de jetons qui est remplacée par la replacement-list . La séquence est terminée par le jeton correspondant ) , en sautant les paires correspondantes de parenthèses gauches et droites intermédiaires.
Pour la version (2), le nombre d'arguments doit être identique au nombre de paramètres dans la définition de la macro. Pour les versions (3,4), le nombre d'arguments ne doit pas être inférieur au nombre de paramètres (
non
(depuis C++20)
comptant
La version (2) de la directive #define définit une macro simple de type fonction.
La version (3) de la directive
#define
définit une macro de type fonction avec un nombre variable d'arguments. Les arguments supplémentaires (appelés
arguments variables
) peuvent être accédés en utilisant l'identifiant
La version (4) de la directive
#define
définit une macro de type fonction avec un nombre variable d'arguments, mais sans arguments réguliers. Les arguments (appelés
arguments variables
) ne peuvent être accédés qu'avec l'identifiant
Note : si un argument d'une macro de type fonction contient des virgules qui ne sont pas protégées par des paires de parenthèses gauche et droite correspondantes (le plus souvent dans les listes d'arguments de template, comme dans assert ( std:: is_same_v < int , int > ) ; ou BOOST_FOREACH ( std:: pair < int , int > p, m ) ), la virgule est interprétée comme un séparateur d'arguments de macro, provoquant une erreur de compilation due à un décompte d'arguments incorrect. Balayage et Remplacement
Notez qu'il est possible de définir une macro pseudo-récursive :
Exécuter ce code
#define EMPTY #define SCAN(x) x #define EXAMPLE_() EXAMPLE #define EXAMPLE(n) EXAMPLE_ EMPTY()(n-1) (n) EXAMPLE(5) SCAN(EXAMPLE(5)) Sortie : EXAMPLE_ ()(5 -1) (5) EXAMPLE_ ()(5 -1 -1) (5 -1) (5) Noms de macros réservésUne unité de traduction qui inclut un en-tête de bibliothèque standard ne peut pas #define ou #undef les noms déclarés dans tout en-tête de bibliothèque standard . Une unité de traduction qui utilise une partie de la bibliothèque standard n'est pas autorisée à #define ou #undef des noms lexicalement identiques à :
Sinon, le comportement est indéfini.
# et ## opérateursDans les macros de type fonction, un opérateur # placé devant un identifiant dans la replacement-list soumet cet identifiant au remplacement des paramètres et l'encadre de guillemets, créant ainsi effectivement un littéral de chaîne. De plus, le préprocesseur ajoute des barres obliques inverses pour échapper les guillemets entourant les littéraux de chaîne intégrés, le cas échéant, et double les barres obliques inverses dans la chaîne si nécessaire. Tous les espaces blancs de début et de fin sont supprimés, et toute séquence d'espaces blancs au milieu du texte (mais pas à l'intérieur des littéraux de chaîne intégrés) est réduite à un seul espace. Cette opération est appelée « stringification ». Si le résultat de la stringification n'est pas un littéral de chaîne valide, le comportement est indéfini.
Un opérateur
##
entre deux identifiants successifs dans la
liste de remplacement
effectue le remplacement des paramètres sur les deux identifiants (qui ne sont pas d'abord développés en tant que macros) puis concatène le résultat. Cette opération est appelée "concaténation" ou "collage de jetons". Seuls les jetons qui forment ensemble un jeton valide peuvent être collés : des identifiants formant un identifiant plus long, des chiffres formant un nombre, ou les opérateurs
Note : certains compilateurs proposent une extension qui permet à
##
d'apparaître après une virgule et avant
#undef directiveLa directive #undef supprime la définition de l' identifiant , c'est-à-dire annule la définition précédente de l' identifiant par la directive #define . Si l'identifiant n'a pas de macro associée, la directive est ignorée. Macros prédéfiniesLes noms de macros suivants sont prédéfinis dans chaque unité de traduction :
Les noms de macros supplémentaires suivants peuvent être prédéfinis par les implémentations :
Les valeurs de ces macros (sauf
Exemple
Exécuter ce code
#include <iostream> // Make function factory and use it #define FUNCTION(name, a) int fun_##name() { return a; } FUNCTION(abcd, 12) FUNCTION(fff, 2) FUNCTION(qqq, 23) #undef FUNCTION #define FUNCTION 34 #define OUTPUT(a) std::cout << "output: " #a << '\n' // Using a macro in the definition of a later macro #define WORD "Hello " #define OUTER(...) WORD #__VA_ARGS__ int main() { std::cout << "abcd: " << fun_abcd() << '\n'; std::cout << "fff: " << fun_fff() << '\n'; std::cout << "qqq: " << fun_qqq() << '\n'; std::cout << FUNCTION << '\n'; OUTPUT(million); //note the lack of quotes std::cout << OUTER(World) << '\n'; std::cout << OUTER(WORD World) << '\n'; } Sortie : abcd: 12 fff: 2 qqq: 23 34 output: million Hello World Hello WORD World Rapports de défautsLes rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
Voir aussi
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||