Alias et typedefs (C++)
Vous pouvez utiliser une déclaration d’alias pour déclarer un nom à utiliser comme synonyme d’un type précédemment déclaré. (Ce mécanisme est également appelé un alias de type de manière informelle). Vous pouvez également utiliser ce mécanisme pour créer un modèle d’alias, qui peut être utile pour les allocateurs personnalisés.
Syntaxe
using identifier = type;
Notes
identifier
Nom de l'alias.
type
Identificateur de type pour lequel vous créez un alias.
Un alias n’introduit pas de nouveau type et ne peut pas changer la signification d’un nom de type existant.
La forme la plus simple d’un alias est équivalente au typedef
mécanisme de C++03 :
// C++11
using counter = long;
// C++03 equivalent:
// typedef long counter;
Ces deux formulaires permettent la création de variables de type counter
. Un élément plus utile est un alias de type comme celui-ci pour std::ios_base::fmtflags
:
// C++11
using fmtfl = std::ios_base::fmtflags;
// C++03 equivalent:
// typedef std::ios_base::fmtflags fmtfl;
fmtfl fl_orig = std::cout.flags();
fmtfl fl_hex = (fl_orig & ~std::cout.basefield) | std::cout.showbase | std::cout.hex;
// ...
std::cout.flags(fl_hex);
Les alias fonctionnent également avec des pointeurs de fonction, mais sont beaucoup plus lisibles que le typedef équivalent :
// C++11
using func = void(*)(int);
// C++03 equivalent:
// typedef void (*func)(int);
// func can be assigned to a function pointer value
void actual_function(int arg) { /* some code */ }
func fptr = &actual_function;
Une limitation du typedef
mécanisme est qu’il ne fonctionne pas avec des modèles. Toutefois, la syntaxe de l'alias de type en C++11 permet la création de modèles d'alias :
template<typename T> using ptr = T*;
// the name 'ptr<T>' is now an alias for pointer to T
ptr<int> ptr_int;
Exemple
L'exemple suivant montre comment utiliser un modèle d'alias avec un allocateur personnalisé, dans ce cas un type de vecteur entier. Vous pouvez remplacer n’importe quel type pour int
créer un alias pratique pour masquer les listes de paramètres complexes dans votre code fonctionnel principal. En utilisant l’allocateur personnalisé tout au long de votre code, vous pouvez améliorer la lisibilité et réduire le risque d’introduire des bogues causés par des fautes de frappe.
#include <stdlib.h>
#include <new>
template <typename T> struct MyAlloc {
typedef T value_type;
MyAlloc() { }
template <typename U> MyAlloc(const MyAlloc<U>&) { }
bool operator==(const MyAlloc&) const { return true; }
bool operator!=(const MyAlloc&) const { return false; }
T * allocate(const size_t n) const {
if (n == 0) {
return nullptr;
}
if (n > static_cast<size_t>(-1) / sizeof(T)) {
throw std::bad_array_new_length();
}
void * const pv = malloc(n * sizeof(T));
if (!pv) {
throw std::bad_alloc();
}
return static_cast<T *>(pv);
}
void deallocate(T * const p, size_t) const {
free(p);
}
};
#include <vector>
using MyIntVector = std::vector<int, MyAlloc<int>>;
#include <iostream>
int main ()
{
MyIntVector foov = { 1701, 1764, 1664 };
for (auto a: foov) std::cout << a << " ";
std::cout << "\n";
return 0;
}
1701 1764 1664
Typedefs
Une typedef
déclaration introduit un nom qui, dans sa portée, devient un synonyme du type donné par la partie déclaration de type de la déclaration.
Vous pouvez utiliser des déclarations typedef pour construire des noms plus courts ou plus explicites pour les types déjà définis par le langage ou pour les types que vous avez déclarés. Les noms typedef vous permettent d'encapsuler des détails d'implémentation susceptibles de changer.
Contrairement aux class
déclarations , et struct
union
enum
aux déclarations, typedef
les déclarations n’introduisent pas de nouveaux types ; elles introduisent de nouveaux noms pour les types existants.
Les noms déclarés à l’aide typedef
de l’espace de noms occupent le même espace de noms que d’autres identificateurs (à l’exception des étiquettes d’instruction). Par conséquent, ils ne peuvent pas utiliser le même identificateur qu’un nom précédemment déclaré, sauf dans une déclaration de type classe. Prenons l’exemple suivant :
// typedef_names1.cpp
// C2377 expected
typedef unsigned long UL; // Declare a typedef name, UL.
int UL; // C2377: redefined.
Les règles de masquage de noms qui concernent d’autres identificateurs régissent également la visibilité des noms déclarés à l’aide typedef
de . Par conséquent, l'exemple suivant est autorisé en C++ :
// typedef_names2.cpp
typedef unsigned long UL; // Declare a typedef name, UL
int main()
{
unsigned int UL; // Redeclaration hides typedef name
}
// typedef UL back in scope
Autre instance de masquage de nom :
// typedef_specifier1.cpp
typedef char FlagType;
int main()
{
}
void myproc( int )
{
int FlagType;
}
Lorsque vous déclarez un identificateur d’étendue locale par le même nom qu’un typedef
ou lorsque vous déclarez un membre d’une structure ou d’une union dans la même étendue ou dans une étendue interne, le spécificateur de type doit être spécifié. Par exemple :
typedef char FlagType;
const FlagType x;
Pour réutiliser le nom FlagType
pour un identificateur, un membre de structure ou un membre d'union, le type doit être fourni :
const int FlagType; // Type specifier required
Il ne suffit pas de déclarer
const FlagType; // Incomplete specification
parce que la FlagType
valeur est prise pour faire partie du type, et non un identificateur qui est redéclaré. Cette déclaration est considérée comme une déclaration illégale, similaire à :
int; // Illegal declaration
Vous pouvez déclarer tout type avec typedef
, y compris des types de pointeur, de fonction et de tableau. Vous pouvez déclarer un nom typedef pour un pointeur vers une structure ou un type union avant de définir la structure ou le type union, tant que la définition a la même visibilité que la déclaration.
Exemples
Une utilisation des typedef
déclarations consiste à rendre les déclarations plus uniformes et plus compactes. Par exemple :
typedef char CHAR; // Character type.
typedef CHAR * PSTR; // Pointer to a string (char *).
PSTR strchr( PSTR source, CHAR target );
typedef unsigned long ulong;
ulong ul; // Equivalent to "unsigned long ul;"
typedef
Pour spécifier des types fondamentaux et dérivés dans la même déclaration, vous pouvez séparer les déclarateurs avec des virgules. Par exemple :
typedef char CHAR, *PSTR;
L’exemple suivant fournit le type DRAWF
pour une fonction qui ne retourne aucune valeur et qui accepte deux arguments int :
typedef void DRAWF( int, int );
Après l’instruction ci-dessus typedef
, la déclaration
DRAWF box;
équivaut à la déclaration
void box( int, int );
typedef
est souvent combiné avec struct
les types définis par l’utilisateur pour déclarer et nommer :
// typedef_specifier2.cpp
#include <stdio.h>
typedef struct mystructtag
{
int i;
double f;
} mystruct;
int main()
{
mystruct ms;
ms.i = 10;
ms.f = 0.99;
printf_s("%d %f\n", ms.i, ms.f);
}
10 0.990000
Redeclaration des typesdefs
La typedef
déclaration peut être utilisée pour redeclarer le même nom pour faire référence au même type. Par exemple :
Fichier source file1.h
:
// file1.h
typedef char CHAR;
Fichier source file2.h
:
// file2.h
typedef char CHAR;
Fichier source prog.cpp
:
// prog.cpp
#include "file1.h"
#include "file2.h" // OK
Le fichier prog.cpp
inclut deux fichiers d’en-tête, qui contiennent typedef
des déclarations pour le nom CHAR
. Tant que les deux déclarations désignent le même type, cette redéclaration est acceptable.
Impossible typedef
de redéfinir un nom qui a été précédemment déclaré en tant que type différent. Considérez cette alternative file2.h
:
// file2.h
typedef int CHAR; // Error
Le compilateur émet une erreur en prog.cpp
raison de la tentative de redéclarer le nom CHAR
pour faire référence à un autre type. Cette stratégie s’étend aux constructions telles que :
typedef char CHAR;
typedef CHAR CHAR; // OK: redeclared as same type
typedef union REGS // OK: name REGS redeclared
{ // by typedef name with the
struct wordregs x; // same meaning.
struct byteregs h;
} REGS;
typedefs en C++ et C
L’utilisation du typedef
spécificateur avec des types de classes est prise en charge en grande partie en raison de la pratique ANSI C de la déclaration de structures non nommées dans les typedef
déclarations. Par exemple, de nombreux programmeurs C utilisent l’idiome suivant :
// typedef_with_class_types1.cpp
// compile with: /c
typedef struct { // Declare an unnamed structure and give it the
// typedef name POINT.
unsigned x;
unsigned y;
} POINT;
L'avantage de ce type de déclaration est qu'il permet des déclarations telles que :
POINT ptOrigin;
plutôt que :
struct point_t ptOrigin;
En C++, la différence entre typedef
les noms et les types réels (déclarées avec les class
mot clé struct
union
, et enum
les noms) est plus distincte. Bien que la pratique C de déclarer une structure sans nom dans une typedef
instruction fonctionne toujours, elle ne fournit aucun avantage notationnel tel qu’il le fait dans C.
// typedef_with_class_types2.cpp
// compile with: /c /W1
typedef struct {
int POINT();
unsigned x;
unsigned y;
} POINT;
L’exemple précédent déclare une classe nommée à l’aide de la syntaxe de classe typedef
non nomméePOINT
. POINT
est considérée comme un nom de classe. Toutefois, les restrictions suivantes s'appliquent aux noms introduits de cette façon :
Le nom (le synonyme) ne peut pas apparaître après un préfixe ,
struct
ouunion
unclass
préfixe.Le nom ne peut pas être utilisé comme constructeur ou nom de destructeur dans une déclaration de classe.
En résumé, cette syntaxe ne fournit aucun mécanisme pour l’héritage, la construction ou la destruction.
Commentaires
https://aka.ms/ContentUserFeedback.
Bientôt disponible : Tout au long de 2024, nous allons supprimer progressivement GitHub Issues comme mécanisme de commentaires pour le contenu et le remplacer par un nouveau système de commentaires. Pour plus d’informations, consultezEnvoyer et afficher des commentaires pour