Declarations
Déclarations sont la manière dont les noms sont introduits (ou réintroduits) dans le programme C++. Toutes les déclarations ne déclarent pas réellement quelque chose, et chaque type d'entité est déclaré différemment. Définitions sont des déclarations qui sont suffisantes pour utiliser l'entité identifiée par le nom.
Une déclaration est l'une des suivantes :
- Définition de fonction
- Déclaration de template (incluant Spécialisation partielle de template )
- Instanciation explicite de template
- Spécialisation explicite de template
- Définition d'espace de noms
- Spécification de liaison
|
(depuis C++11) |
-
Déclaration vide (
;) - Une déclaration de fonction sans decl-specifier-seq :
attr
(facultatif)
déclarateur
;
|
|||||||||
| attr | - | (since C++11) séquence d'un nombre quelconque d' attributs |
| declarator | - | un déclarateur de fonction |
- Cette déclaration doit déclarer un constructeur, un destructeur, ou une fonction de conversion conversion function . Elle ne peut être utilisée que comme partie d'une template declaration , explicit specialization , ou explicit instantiation.
- block-declaration (une déclaration qui peut apparaître à l'intérieur d'un bloc ), qui, à son tour, peut être l'une des suivantes :
| (depuis C++11) |
| (depuis C++20) | |
|
(depuis C++11) |
-
- déclaration simple
Table des matières |
Déclaration simple
Une simple déclaration est une instruction qui introduit, crée et optionnellement initialise un ou plusieurs identifiants, généralement des variables.
decl-specifier-seq
init-declarator-list
(optionnel)
;
|
(1) | ||||||||
attr
decl-specifier-seq
init-declarator-list
;
|
(2) | (depuis C++11) | |||||||
| decl-specifier-seq | - | séquence de spécificateurs |
| init-declarator-list | - | liste séparée par des virgules de init-declarator s (voir ci-dessous) |
| attr | - | séquence d'un nombre quelconque d' attributs |
init-declarator-list
ne peut être omis que lors de la déclaration d'une classe nommée ou d'une énumération nommée.
|
Une déclaration de liaison structurée est également une déclaration simple. |
(depuis C++17) |
La syntaxe de
init-declarator
est définie comme suit :
| declarator initializer | (1) | ||||||||
| declarator requires-clause (optionnel) contract-specs (optionnel) | (2) | ||||||||
| declarator | - | un declarator |
| initializer | - | un initializer |
| requires-clause | - | (since C++20) une requires clause |
| contract-specs | - | (since C++26) une liste de function contract specifiers |
|
requires-clause ne peut apparaître que si declarator déclare une fonction template . |
(depuis C++20) |
|
contract-specs ne peut apparaître que si declarator déclare une fonction ou un template de fonction. |
(depuis C++26) |
Spécificateurs
Spécificateurs de déclaration ( decl-specifier-seq ) est une séquence des spécificateurs suivants, séparés par des espaces, dans n'importe quel ordre :
-
le
typedefspécificateur. S'il est présent, la déclaration entière est une déclaration typedef et chaque déclarateur introduit un nouveau nom de type, pas un objet ou une fonction. -
spécificateurs de fonction (
inline,virtual,explicit), uniquement autorisés dans les déclarations de fonction .
|
(depuis C++17) |
-
le
friendspécificateur, autorisé dans les déclarations de classes et de fonctions.
|
(depuis C++11) |
|
(depuis C++20) |
- spécificateur de classe de stockage ( register , (jusqu'en C++17) static , thread_local , (depuis C++11) extern , mutable ). Un seul spécificateur de classe de stockage est autorisé , sauf que thread_local peut apparaître avec extern ou static (depuis C++11) .
- Spécificateurs de type ( type-specifier-seq ), une séquence de spécificateurs qui nomme un type. Le type de chaque entité introduite par la déclaration est ce type, optionnellement modifié par le déclarateur (voir ci-dessous). Cette séquence de spécificateurs est également utilisée par type-id . Seuls les spécificateurs suivants font partie de type-specifier-seq , dans n'importe quel ordre :
-
- spécificateur de classe
- spécificateur d'énumération
- spécificateur de type simple
| (depuis C++11) | |
| (depuis C++26) |
-
-
- nom de classe précédemment déclaré (optionnellement qualifié )
- nom d'énumération précédemment déclaré (optionnellement qualifié )
- nom de typedef ou alias de type (depuis C++11) précédemment déclaré (optionnellement qualifié )
- nom de template avec arguments de template (optionnellement qualifié , optionnellement en utilisant le désambiguïsateur de template )
-
|
(depuis C++17) |
-
-
- le mot-clé class , struct , ou union , suivi de l'identifiant (optionnellement qualifié ), précédemment défini comme nom d'une classe.
- le mot-clé class , struct , ou union , suivi du nom du template avec ses arguments (optionnellement qualifié , optionnellement en utilisant le template disambiguateur ), précédemment défini comme nom d'un template de classe.
- le mot-clé enum suivi de l'identifiant (optionnellement qualifié ), précédemment déclaré comme nom d'une énumération.
-
-
un seul spécificateur de type est autorisé dans une séquence de spécificateurs de déclaration, avec les exceptions suivantes :
- const peut être combiné avec n'importe quel spécificateur de type sauf lui-même.
- volatile peut être combiné avec n'importe quel spécificateur de type sauf lui-même.
- signed ou unsigned peuvent être combinés avec char , long , short , ou int .
- short ou long peuvent être combinés avec int .
- long peut être combiné avec double .
|
(depuis C++11) |
Attributs peuvent apparaître dans decl-specifier-seq , auquel cas ils s'appliquent au type déterminé par les spécificateurs précédents.
Les répétitions de tout spécificateur dans une decl-specifier-seq , telles que const static const , ou virtual inline virtual sont des erreurs , sauf que long est autorisé à apparaître deux fois (depuis C++11) .
Déclarateurs
Chaque init-declarator dans une init-declarator-list S D1, D2, D3 ; est traité comme s'il s'agissait d'une déclaration autonome avec les mêmes spécificateurs : S D1 ; S D2 ; S D3 ; .
Chaque déclarateur introduit exactement un objet, référence, fonction ou (pour les déclarations typedef) alias de type, dont le type est fourni par decl-specifier-seq et optionnellement modifié par des opérateurs tels que & (référence vers) ou [ ] (tableau de) ou ( ) (fonction retournant) dans le déclarateur. Ces opérateurs peuvent être appliqués récursivement, comme montré ci-dessous.
Un déclarateur est l'un des éléments suivants :
| unqualified-id attr (optionnel) | (1) | ||||||||
| qualified-id attr (optionnel) | (2) | ||||||||
...
identifier
attr
(optionnel)
|
(3) | (depuis C++11) | |||||||
*
attr
(optionnel)
cv
(optionnel)
declarator
|
(4) | ||||||||
nested-name-specifier
*
attr
(optionnel)
cv
(optionnel)
declarator
|
(5) | ||||||||
&
attr
(optionnel)
declarator
|
(6) | ||||||||
&&
attr
(optionnel)
declarator
|
(7) | (depuis C++11) | |||||||
noptr-declarator
[
constant-expression
(optionnel)
]
attr
(optionnel)
|
(8) | ||||||||
noptr-declarator
(
parameter-list
)
cv
(optionnel)
ref
(optionnel)
except
(optionnel)
attr
(optionnel)
|
(9) | ||||||||
(
declarator
)
|
(10) | ||||||||
D
comme un pointeur vers le type déterminé par
decl-specifier-seq
S
.
D
comme un pointeur vers membre de
C
de type déterminé par
decl-specifier-seq
S
.
nested-name-specifier
est une
séquence de noms et d'opérateurs de résolution de portée
::
D
comme une référence Lvalue vers le type déterminé par
decl-specifier-seq
S
.
D
comme une référence à valeur résiduelle vers le type déterminé par
decl-specifier-seq
S
.
|
Dans tous les cas, attr est une séquence optionnelle d' attributs . Lorsqu'il apparaît immédiatement après l'identifiant, il s'applique à l'objet étant déclaré. |
(since C++11) |
cv est une séquence de qualificateurs const et volatile , où chaque qualificateur peut apparaître au plus une fois dans la séquence.
|
Cette section est incomplète
Motif : expliquer les règles de masquage des noms de déclaration ; comment une déclaration de variable/fonction masque une classe (mais pas un typedef) portant le même nom |
Notes
Lorsqu'une block-declaration apparaît à l'intérieur d'un bloc , et qu'un identifiant introduit par une déclaration a été précédemment déclaré dans un bloc externe, la déclaration externe est masquée pour le reste du bloc.
Si une déclaration introduit une variable avec une durée de stockage automatique, elle est initialisée lorsque son instruction de déclaration est exécutée. Toutes les variables automatiques déclarées dans un bloc sont détruites à la sortie du bloc (peu importe comment le bloc est quitté : via exception , goto , ou en atteignant sa fin), dans l'ordre inverse de leur ordre d'initialisation.
Exemple
Note : cet exemple démontre comment certaines déclarations complexes sont analysées en termes de grammaire du langage. D'autres mnémoniques populaires sont : la règle en spirale , la lecture de l'intérieur vers l'extérieur , et la déclaration reflète l'utilisation . Il existe également un analyseur automatisé sur https://cdecl.org .
#include <type_traits> struct S { int member; // decl-specifier-seq is "int" // declarator is "member" } obj, *pObj(&obj); // decl-specifier-seq is "struct S { int member; }" // declarator "obj" declares an object of type S // declarator "*pObj" declares a pointer to S, // and initializer "(&obj)" initializes it int i = 1, *p = nullptr, f(), (*pf)(double); // decl-specifier-seq is "int" // declarator "i" declares a variable of type int, // and initializer "= 1" initializes it // declarator "*p" declares a variable of type int*, // and initializer "= nullptr" initializes it // declarator "f()" declares (but doesn't define) // a function taking no arguments and returning int // declarator "(*pf)(double)" declares a pointer to function // taking double and returning int int (*(*var1)(double))[3] = nullptr; // decl-specifier-seq is "int" // declarator is "(*(*var1)(double))[3]" // initializer is "= nullptr" // 1. declarator "(*(*var1)(double))[3]" is an array declarator: // Type declared is: "(*(*var1)(double))" array of 3 elements // 2. declarator "(*(*var1)(double))" is a pointer declarator: // Type declared is: "(*var1)(double)" pointer to array of 3 elements // 3. declarator "(*var1)(double)" is a function declarator: // Type declared is: "(*var1)" function taking "(double)", // returning pointer to array of 3 elements. // 4. declarator "(*var1)" is a pointer declarator: // Type declared is: "var1" pointer to function taking "(double)", // returning pointer to array of 3 elements. // 5. declarator "var1" is an identifier. // This declaration declares the object var1 of type "pointer to function // taking double and returning pointer to array of 3 elements of type int" // The initializer "= nullptr" provides the initial value of this pointer. // C++11 alternative syntax: auto (*var2)(double) -> int (*)[3] = nullptr; // decl-specifier-seq is "auto" // declarator is "(*var2)(double) -> int (*)[3]" // initializer is "= nullptr" // 1. declarator "(*var2)(double) -> int (*)[3]" is a function declarator: // Type declared is: "(*var2)" function taking "(double)", returning "int (*)[3]" // ... int main() { static_assert(std::is_same_v<decltype(var1), decltype(var2)>); }
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Applicable à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| CWG 482 | C++98 | les déclarateurs des redéclarations ne pouvaient pas être qualifiés | déclarateurs qualifiés autorisés |
| CWG 569 | C++98 | un point-virgule isolé n'était pas une déclaration valide |
c'est une déclaration vide,
qui n'a aucun effet |
| CWG 1830 | C++98 | la répétition d'un spécificateur de fonction dans une decl-specifier-seq était autorisée | la répétition est interdite |
Voir aussi
|
Documentation C
pour
Déclarations
|