Type
Objets , références , fonctions incluant les spécialisations de modèles de fonction , et expressions possèdent une propriété appelée type , qui restreint à la fois les opérations permises pour ces entités et fournit une signification sémantique aux séquences de bits autrement génériques.
Table des matières |
Classification des types
Le système de types C++ comprend les types suivants :
- types fondamentaux (voir aussi std::is_fundamental ):
-
- le type void (voir aussi std::is_void );
|
(depuis C++11) |
-
- types arithmétiques (voir aussi std::is_arithmetic ) :
-
- types entiers (incluant les versions cv-qualifiées , voir aussi std::is_integral , un synonyme de type entier est integer type) :
-
- le type bool ;
- types caractères :
-
- types caractères étroits :
-
- types caractères ordinaires : char , signed char , unsigned char [1]
|
(depuis C++20) |
-
-
-
-
- types de caractères larges : char16_t , char32_t , (depuis C++11) wchar_t ;
- types entiers signés :
-
- types entiers signés standard : signed char , short , int , long , long long ;
-
-
-
|
(depuis C++11) |
-
-
-
- types entiers non signés :
-
- types entiers non signés standards : unsigned char , unsigned short , unsigned , unsigned long , unsigned long long ;
-
-
|
(depuis C++11) |
-
-
- types à virgule flottante (voir aussi std::is_floating_point ) :
-
- types à virgule flottante standard : float , double , long double et leurs versions qualifiées cv ;
-
|
(depuis C++23) |
- types composés (voir aussi std::is_compound ) :
-
- types référence (voir aussi std::is_reference ):
-
- types référence lvalue (voir aussi std::is_lvalue_reference ):
-
- référence lvalue vers des types objet ;
- référence lvalue vers des types fonction ;
|
(depuis C++11) |
-
- types pointeur (voir aussi std::is_pointer ):
- types pointeur-vers-membre (voir aussi std::is_member_pointer ):
-
- types pointeur-vers-membre-de-données (voir aussi std::is_member_object_pointer );
- types pointeur-vers-fonction-membre (voir aussi std::is_member_function_pointer );
- types tableau (voir aussi std::is_array );
- types fonction (voir aussi std::is_function );
- types énumération (voir aussi std::is_enum );
|
(depuis C++11) |
-
-
- types non-union (voir aussi std::is_class );
- types union (voir aussi std::is_union ).
-
- ↑ signed char et unsigned char sont des types de caractères étroits, mais ils ne sont pas des types de caractères. En d'autres termes, l'ensemble des types de caractères étroits n'est pas un sous-ensemble de l'ensemble des types de caractères.
Pour chaque type non qualifié-cv autre que référence et fonction, le système de types prend en charge trois versions supplémentaires qualifiées-cv de ce type ( const , volatile , et const volatile ).
Autres catégories
Un type d'objet (voir aussi std::is_object ) est un type (éventuellement qualifié cv) qui n'est pas un type fonction, pas un type référence, et pas un void (éventuellement qualifié cv).
Les types suivants sont collectivement appelés types scalaires (voir aussi std::is_scalar ):
- types arithmétiques
- types énumération
- types pointeur
- types pointeur-vers-membre
| (depuis C++11) |
- versions qualifiées cv de ces types
Les types suivants sont collectivement appelés types à durée de vie implicite :
- types scalaires
- types de classes à durée de vie implicite
- types tableau
- versions qualifiées cv de ces types
|
Les types suivants sont collectivement appelés types trivialement copiables :
Les types suivants sont collectivement appelés types à disposition standard :
|
(depuis C++11) |
| Diagramme hiérarchique des traits de type |
|---|
|
Remarque : Les éléments de l'image SVG sont cliquables, mais vous devez d'abord ouvrir le diagramme dans un nouvel onglet du navigateur |
Catégories dépréciées
|
Les types suivants sont collectivement appelés types POD (voir aussi std::is_pod ) :
|
(obsolète en C++20) |
|
Les types suivants sont collectivement appelés types triviaux (voir aussi std::is_trivial ) :
|
(depuis C++11)
(obsolète en C++26) |
Type défini par le programme
Une spécialisation définie par le programme est une spécialisation explicite ou une spécialisation partielle qui ne fait pas partie de la bibliothèque standard C++ et n'est pas définie par l'implémentation.
Un type défini par le programme est l'un des types suivants :
- Un type non- closure (depuis C++11) type classe ou type énumération qui ne fait pas partie de la bibliothèque standard C++ et n'est pas défini par l'implémentation.
|
(depuis C++11) |
- Une instanciation d'une spécialisation définie par le programme.
Nommage des types
Un nom peut être déclaré pour faire référence à un type au moyen de :
- class déclaration ;
- union déclaration ;
- enum déclaration ;
- typedef déclaration ;
- type alias déclaration.
Les types qui n'ont pas de noms doivent souvent être référencés dans les programmes C++ ; la syntaxe pour cela est connue sous le nom de
type-id
. La syntaxe du type-id qui nomme le type
T
est exactement la syntaxe d'une
déclaration
d'une variable ou fonction de type
T
, avec l'identifiant omis, sauf que le
decl-specifier-seq
de la grammaire de déclaration est contraint à
type-specifier-seq
, et que de nouveaux types peuvent être définis uniquement si le type-id apparaît du côté droit d'une déclaration d'alias de type non-template.
int* p; // déclaration d'un pointeur vers int static_cast<int*>(p); // type-id est "int*" int a[3]; // déclaration d'un tableau de 3 int new int[3]; // type-id est "int[3]" (appelé new-type-id) int (*(*x[2])())[3]; // déclaration d'un tableau de 2 pointeurs vers des fonctions // retournant un pointeur vers un tableau de 3 int new (int (*(*[2])())[3]); // type-id est "int (*(*[2])())[3]" void f(int); // déclaration d'une fonction prenant int et retournant void std::function<void(int)> x = f; // paramètre de type template est un type-id "void(int)" std::function<auto(int) -> void> y = f; // identique std::vector<int> v; // déclaration d'un vecteur de int sizeof(std::vector<int>); // type-id est "std::vector<int>" struct { int x; } b; // crée un nouveau type et déclare un objet b de ce type sizeof(struct { int x; }); // erreur : impossible de définir de nouveaux types dans une expression sizeof using t = struct { int x; }; // crée un nouveau type et déclare t comme alias de ce type sizeof(static int); // erreur : spécificateurs de classe de stockage ne font pas partie de type-specifier-seq std::function<inline void(int)> f; // erreur : les spécificateurs de fonction non plus
La partie déclarateur de la grammaire de déclaration avec le nom supprimé est appelée abstract-declarator .
Type-id peut être utilisé dans les situations suivantes :
- pour spécifier le type cible dans les expressions de conversion ;
-
comme arguments de
sizeof,alignof,alignas,new, ettypeid; - sur le côté droit d'une déclaration d'alias de type ;
- comme type de retour final d'une déclaration de fonction ;
- comme argument par défaut d'un paramètre de template de type ;
- comme argument de template pour un paramètre de template de type ;
| (jusqu'à C++17) |
Le type-id peut être utilisé avec certaines modifications dans les situations suivantes :
- dans la liste des paramètres d'une fonction (lorsque le nom du paramètre est omis), le type-id utilise decl-specifier-seq au lieu de type-specifier-seq (en particulier, certains spécificateurs de classe de stockage sont autorisés) ;
- dans le nom d'une fonction de conversion définie par l'utilisateur , le déclarateur abstrait ne peut pas inclure d'opérateurs de fonction ou de tableau.
|
Cette section est incomplète
Raison : 8.2[dcl.ambig.res] si elle peut être résumée de manière concise |
|
Cette section est incomplète
Raison : mentionner et lier à decltype et auto |
Spécificateur de type élaboré
Les spécificateurs de type élaborés peuvent être utilisés pour faire référence à un nom de classe précédemment déclaré (classe, struct ou union) ou à un nom d'énumération précédemment déclaré, même si le nom était masqué par une déclaration de non-type . Ils peuvent également être utilisés pour déclarer de nouveaux noms de classe.
Voir elaborated type specifier pour plus de détails.
Type statique
Le type d'une expression qui résulte de l'analyse à la compilation du programme est connu comme le static type de l'expression. Le static type ne change pas pendant l'exécution du programme.
Type dynamique
Si une expression glvalue fait référence à un objet polymorphe , le type de son objet le plus dérivé est appelé le type dynamique.
// donné struct B { virtual ~B() {} }; // polymorphic type struct D : B {}; // polymorphic type D d; // objet le plus dérivé B* ptr = &d; // le type statique de (*ptr) est B // le type dynamique de (*ptr) est D
Pour les expressions prvalue, le type dynamique est toujours identique au type statique.
Type incomplet
Les types suivants sont des types incomplets :
- le type void (éventuellement cv -qualifié);
-
types d'objets incomplètement définis
:
- type classe qui a été déclaré (par ex. par une déclaration anticipée ) mais non défini;
- tableau de taille inconnue ;
- tableau d'éléments de type incomplet;
- type énumération depuis le point de déclaration jusqu'à ce que son type sous-jacent soit déterminé.
Tous les autres types sont complets.
L'un des contextes suivants exige que le type
T
soit complet :
-
définition
ou appel d'une fonction avec un type de retour
Tou un type d'argumentT; -
définition
d'un objet de type
T; -
déclaration d'un
membre de données non statique de classe
de type
T; -
newexpression pour un objet de typeTou un tableau dont le type d'élément estT; -
conversion lvalue-vers-rvalue
appliquée à une glvalue de type
T; -
une conversion
implicite
ou
explicite
vers le type
T; -
une
conversion standard
,
dynamic_cast, oustatic_castvers le type T * ou T & , sauf lors de la conversion depuis la constante de pointeur nul ou depuis un pointeur vers void éventuellement qualifié cv ; -
opérateur d'accès aux membres de classe
appliqué à une expression de type
T; -
typeid,sizeof, oualignofappliqué au typeT; -
opérateur arithmétique
appliqué à un pointeur vers
T; -
définition d'une classe avec une classe de base
T; -
assignation à une lvalue de type
T; -
un
gestionnaire
de type
T, T & , ou T * .
(En général, lorsque la taille et la disposition de
T
doivent être connues.)
Si l'une de ces situations se produit dans une unité de traduction, la définition du type doit apparaître dans la même unité de traduction. Sinon, elle n'est pas requise.
Un type d'objet incomplètement défini peut être complété :
- Un type de classe (tel que class X ) peut être considéré comme incomplet à un moment donné dans une unité de traduction et considéré comme complet ultérieurement ; le type class X est le même type aux deux moments :
struct X; // déclaration de X, aucune définition fournie pour l'instant extern X* xp; // xp est un pointeur vers un type incomplet : // la définition de X n'est pas accessible void foo() { xp++; // incorrect : X est incomplet } struct X { int i; }; // définition de X X x; // OK : la définition de X est accessible void bar() { xp = &x; // OK : le type est « pointeur vers X » xp++; // OK : X est complet }
- Le type déclaré d'un objet tableau peut être un tableau de type classe incomplet et donc incomplet ; si le type classe est complété ultérieurement dans l'unité de traduction, le type tableau devient complet ; le type tableau à ces deux points est le même type.
-
Le type déclaré d'un objet tableau peut être un tableau de taille inconnue et donc être incomplet à un moment donné dans une unité de traduction et complet ultérieurement ; les types tableau à ces deux points ("tableau de taille inconnue de
T" et "tableau de NT") sont des types différents.
Le type d'un pointeur ou d'une référence vers un tableau de taille inconnue pointe ou réfère définitivement vers un type incomplet. Un tableau de taille inconnue désigné par une
typedef
déclaration réfère définitivement à un type incomplet. Dans les deux cas, le type tableau ne peut être complété :
extern int arr[]; // le type de arr est incomplet typedef int UNKA[]; // UNKA est un type incomplet UNKA* arrp; // arrp est un pointeur vers un type incomplet UNKA** arrpp; void foo() { arrp++; // erreur : UNKA est un type incomplet arrpp++; // OK : sizeof UNKA* est connu } int arr[10]; // maintenant le type de arr est complet void bar() { arrp = &arr; // OK : conversion de qualification (depuis C++20) arrp++; // erreur : UNKA ne peut pas être complété }
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 | Appliqué à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| CWG 328 | C++98 |
les membres de classe de type incomplet n'étaient pas interdits
si un objet du type classe n'était jamais créé |
les membres de données non statiques de classe
doivent être complets |
| CWG 977 | C++98 |
le moment où un type énumération devient
complet dans sa définition n'était pas clair |
le type est complet une fois que le
type sous-jacent est déterminé |
| CWG 1362 | C++98 |
les conversions définies par l'utilisateur vers le type
T*
ou
T&
exigeaient
T
d'être complet
|
non requis |
| CWG 2006 | C++98 | les types void qualifiés cv étaient des types objet et des types complets | exclus des deux catégories |
| CWG 2448 | C++98 | seuls les types non qualifiés cv pouvaient être des types entiers et à virgule flottante | autorise les types qualifiés cv |
| CWG 2630 | C++98 |
il n'était pas clair si une classe est considérée comme complète en dehors
de l'unité de traduction où la définition de la classe apparaît |
la classe est complète
si sa définition est accessible dans ce cas |
| CWG 2643 | C++98 |
le type d'un pointeur vers un tableau de taille inconnue
ne pouvait pas être complété (mais il est déjà complet) |
le type de tableau pointé
ne peut pas être complété |
| LWG 2139 | C++98 | la signification de "type défini par l'utilisateur" n'était pas claire |
définit et utilise "type
défini par le programme" à la place |
| LWG 3119 | C++11 | il n'était pas clair si les types de fermeture sont des types définis par le programme | clarifié |
Références
- Norme C++23 (ISO/CEI 14882:2024) :
-
- 6.8.2 Types fondamentaux [basic.fundamental]
- Norme C++20 (ISO/CEI 14882:2020) :
-
- 6.8.2 Types fondamentaux [basic.fundamental]
- Norme C++17 (ISO/CEI 14882:2017) :
-
- 6.9.1 Types fondamentaux [basic.fundamental]
- Norme C++14 (ISO/CEI 14882:2014) :
-
- 3.9.1 Types fondamentaux [basic.fundamental]
- Norme C++11 (ISO/CEI 14882:2011) :
-
- 3.9.1 Types fondamentaux [basic.fundamental]
- Norme C++98 (ISO/CEI 14882:1998) :
-
- 3.9.1 Types fondamentaux [basic.fundamental]
Voir aussi
| Type traits | Interfaces basées sur des templates à la compilation pour interroger les propriétés des types |
|
Documentation C
pour
Type
|
|
Liens externes
| 1. | Arborescence des types C++0x de Howard Hinnant |