Type
Objekte , Referenzen , Funktionen einschließlich Funktions-Template-Spezialisierungen , und Ausdrücke besitzen eine Eigenschaft namens Typ , die sowohl die Operationen einschränkt, die für diese Entitäten erlaubt sind, als auch semantische Bedeutung für die ansonsten generischen Bitsequenzen bereitstellt.
Inhaltsverzeichnis |
Typklassifizierung
Das C++-Typsystem besteht aus den folgenden Typen:
- Grunddatentypen (siehe auch std::is_fundamental ):
-
- der Typ void (siehe auch std::is_void );
|
(seit C++11) |
-
- Arithmetische Typen (siehe auch std::is_arithmetic ):
-
- Ganzzahlige Typen (einschließlich cv-qualifizierter Versionen , siehe auch std::is_integral , ein Synonym für Ganzzahltyp ist Integer-Typ):
-
- der Typ bool ;
- Zeichentypen:
-
- Schmale Zeichentypen:
-
- Gewöhnliche Zeichentypen: char , signed char , unsigned char [1]
|
(seit C++20) |
-
-
-
-
- Breitzeichen-Typen: char16_t , char32_t , (seit C++11) wchar_t ;
- Ganzzahltypen mit Vorzeichen:
-
- Standard-Ganzzahltypen mit Vorzeichen: signed char , short , int , long , long long ;
-
-
-
|
(since C++11) |
-
-
-
- vorzeichenlose Ganzzahltypen:
-
- Standard vorzeichenlose Ganzzahltypen: unsigned char , unsigned short , unsigned , unsigned long , unsigned long long ;
-
-
|
(seit C++11) |
-
-
- Gleitkommatypen (siehe auch std::is_floating_point ):
-
- Standard-Gleitkommatypen: float , double , long double und ihre CV-qualifizierten Versionen ;
-
|
(seit C++23) |
- zusammengesetzte Typen (siehe auch std::is_compound ):
-
- Referenztypen (siehe auch std::is_reference ):
-
- Lvalue-Referenztypen (siehe auch std::is_lvalue_reference ):
-
- Lvalue-Referenz auf Objekttypen;
- Lvalue-Referenz auf Funktionstypen;
|
(seit C++11) |
-
- Zeigertypen (siehe auch std::is_pointer ):
- Zeiger-auf-Mitglied-Typen (siehe auch std::is_member_pointer ):
-
- Zeiger-auf-Datenmitglied -Typen (siehe auch std::is_member_object_pointer );
- Zeiger-auf-Mitgliedsfunktion -Typen (siehe auch std::is_member_function_pointer );
- Arraytypen (siehe auch std::is_array );
- Funktionstypen (siehe auch std::is_function );
- Aufzählungstypen (siehe auch std::is_enum );
|
(seit C++11) |
-
-
- Nicht-Union-Typen (siehe auch std::is_class );
- Union-Typen (siehe auch std::is_union ).
-
- ↑ signed char und unsigned char sind Narrow-Character-Typen, aber sie sind keine Character-Typen. Mit anderen Worten: Die Menge der Narrow-Character-Typen ist keine Teilmenge der Menge der Character-Typen.
Für jeden nicht-cv-qualifizierten Typ, außer Referenz- und Funktionstypen, unterstützt das Typsystem drei zusätzliche cv-qualifizierte Versionen dieses Typs ( const , volatile , und const volatile ).
Weitere Kategorien
Ein Objekttyp (siehe auch std::is_object ) ist ein (möglicherweise cv-qualifizierter) Typ, der kein Funktionstyp, kein Referenztyp und kein (möglicherweise cv-qualifizierter) void ist.
Die folgenden Typen werden zusammen als Skalartypen bezeichnet (siehe auch std::is_scalar ):
- arithmetische Typen
- Aufzählungstypen
- Zeigertypen
- Zeiger-auf-Mitglieder-Typen
| (seit C++11) |
- cv-qualifizierte Versionen dieser Typen
Die folgenden Typen werden zusammen als implicit-lifetime types bezeichnet:
- Skalare Typen
- Implicit-Lifetime-Klassentypen
- Array-Typen
- CV-qualifizierte Versionen dieser Typen
|
Die folgenden Typen werden zusammenfassend als trivially copyable types bezeichnet:
Die folgenden Typen werden zusammenfassend als standard-layout types bezeichnet:
|
(since C++11) |
| Diagramm der Type-Traits-Hierarchie |
|---|
|
Hinweis: Elemente des SVG-Bildes sind anklickbar, aber Sie müssen das Diagramm zuerst in einem neuen Browser-Tab öffnen |
Veraltete Kategorien
|
Die folgenden Typen werden zusammenfassend als POD-Typen bezeichnet (siehe auch std::is_pod ):
|
(in C++20 veraltet) |
|
Die folgenden Typen werden zusammenfassend als triviale Typen bezeichnet (siehe auch std::is_trivial ):
|
(seit C++11)
(in C++26 veraltet) |
Programmdatentyp
Eine program-defined specialization ist eine explicit specialization oder partial specialization , die nicht Teil der C++ standard library ist und nicht durch die Implementierung definiert wird.
Ein programmdefinierter Typ ist einer der folgenden Typen:
- Ein Nicht- Closure (seit C++11) Klassentyp oder Aufzählungstyp der nicht Teil der C++-Standardbibliothek ist und nicht durch die Implementierung definiert wird.
|
(since C++11) |
- Eine Instanziierung einer programmdefinierten Spezialisierung.
Typbenennung
Ein Name kann deklariert werden, um auf einen Typ zu verweisen, mittels:
- class Deklaration;
- union Deklaration;
- enum Deklaration;
- typedef Deklaration;
- type alias Deklaration.
Typen, die keine Namen haben, müssen oft in C++-Programmen referenziert werden; die Syntax dafür ist bekannt als
type-id
. Die Syntax der type-id, die den Typ
T
benennt, ist exakt die Syntax einer
Deklaration
einer Variable oder Funktion vom Typ
T
, wobei der Identifikator weggelassen wird, mit der Ausnahme, dass
decl-specifier-seq
der Deklarationsgrammatik eingeschränkt ist auf
type-specifier-seq
, und dass neue Typen nur definiert werden dürfen, wenn die type-id auf der rechten Seite einer Nicht-Template-Typalias-Deklaration erscheint.
int* p; // Deklaration eines Zeigers auf int static_cast<int*>(p); // type-id ist "int*" int a[3]; // Deklaration eines Arrays von 3 int new int[3]; // type-id ist "int[3]" (genannt new-type-id) int (*(*x[2])())[3]; // Deklaration eines Arrays von 2 Zeigern auf Funktionen // die Zeiger auf Arrays von 3 int zurückgeben new (int (*(*[2])())[3]); // type-id ist "int (*(*[2])())[3]" void f(int); // Deklaration einer Funktion, die int nimmt und void zurückgibt std::function<void(int)> x = f; // Typ-Template-Parameter ist eine type-id "void(int)" std::function<auto(int) -> void> y = f; // dasselbe std::vector<int> v; // Deklaration eines Vektors von int sizeof(std::vector<int>); // type-id ist "std::vector<int>" struct { int x; } b; // erzeugt einen neuen Typ und deklariert ein Objekt b dieses Typs sizeof(struct { int x; }); // Fehler: Neue Typen können nicht in sizeof-Ausdrücken definiert werden using t = struct { int x; }; // erzeugt einen neuen Typ und deklariert t als Alias dieses Typs sizeof(static int); // Fehler: Speicherklassenspezifizierer sind nicht Teil der type-specifier-seq std::function<inline void(int)> f; // Fehler: ebenso wenig sind Funktionsspezifizierer
Der Deklarator -Teil der Deklarationsgrammatik ohne den Namen wird als abstrakter Deklarator bezeichnet.
Type-id kann in den folgenden Situationen verwendet werden:
- um den Zieltyp in Cast-Ausdrücken anzugeben;
-
als Argumente für
sizeof,alignof,alignas,newundtypeid; - auf der rechten Seite einer Typalias -Deklaration;
- als trailing return type einer Funktions -Deklaration;
- als Standardargument eines Template-Typparameters ;
- als Template-Argument für einen Template-Typparameter ;
| (bis C++17) |
Type-id kann mit einigen Modifikationen in den folgenden Situationen verwendet werden:
- in der Parameterliste einer Funktion (wenn der Parametername weggelassen wird), verwendet type-id decl-specifier-seq anstelle von type-specifier-seq (insbesondere sind einige Speicherklassenspezifizierer erlaubt);
- im Namen einer benutzerdefinierten Konvertierungsfunktion , kann der abstrakte Deklarator keine Funktions- oder Arrayoperatoren enthalten.
|
Dieser Abschnitt ist unvollständig
Grund: 8.2[dcl.ambig.res] wenn es kompakt zusammengefasst werden kann |
|
Dieser Abschnitt ist unvollständig
Grund: Erwähnung und Verlinkung zu decltype und auto |
Elaborierte Typspezifizierer
Ausgeführte Typspezifizierer können verwendet werden, um auf einen zuvor deklarierten Klassennamen (class, struct oder union) oder einen zuvor deklarierten Enum-Namen zu verweisen, selbst wenn der Name durch eine Nicht-Typ-Deklaration verborgen wurde . Sie können auch verwendet werden, um neue Klassennamen zu deklaren.
Siehe elaborated type specifier für Details.
Statischer Typ
Der Typ eines Ausdrucks, der sich aus der Compilezeit-Analyse des Programms ergibt, wird als statischer Typ des Ausdrucks bezeichnet. Der statische Typ ändert sich nicht während der Ausführung des Programms.
Dynamischer Typ
Wenn ein glvalue expression auf ein polymorphic object verweist, wird der Typ seines am stärksten abgeleiteten Objekts als der dynamische Typ bezeichnet.
// gegeben struct B { virtual ~B() {} }; // polymorpher Typ struct D : B {}; // polymorpher Typ D d; // am meisten abgeleitetes Objekt B* ptr = &d; // der statische Typ von (*ptr) ist B // der dynamische Typ von (*ptr) ist D
Für prvalue-Ausdrücke ist der dynamische Typ immer derselbe wie der statische Typ.
Unvollständiger Typ
Die folgenden Typen sind unvollständige Typen :
- der Typ void (möglicherweise cv -qualifiziert);
-
unvollständig definierte Objekttypen
:
- Klassentyp, der deklariert (z.B. durch Vorwärtsdeklaration ), aber nicht definiert wurde;
- Array unbekannter Größe ;
- Array von Elementen unvollständigen Typs;
- Aufzählungstyp vom Punkt der Deklaration bis zur Bestimmung seines zugrundeliegenden Typs.
Alle anderen Typen sind vollständig.
Jeder der folgenden Kontexte erfordert, dass der Typ
T
vollständig ist:
-
Definition
von oder Aufruf einer Funktion mit Rückgabetyp
Toder ParametertypT; -
Definition
eines Objekts vom Typ
T; -
Deklaration eines
nicht-statischen Klassen-Datenmembers
vom Typ
T; -
newExpression für ein Objekt vom TypToder ein Array mit ElementtypT; -
Lvalue-zu-Rvalue-Konvertierung
angewendet auf einen Lvalue vom Typ
T; -
eine
implizite
oder
explizite
Konvertierung zum Typ
T; -
eine
Standardkonvertierung
,
dynamic_cast, oderstatic_castzum Typ T * oder T & , außer bei Konvertierung von der Nullzeigerkonstante oder von einem Zeiger auf möglicherweise cv-qualifiziertes void ; -
Klassen-Member-Zugriffsoperator
angewendet auf einen Ausdruck vom Typ
T; -
typeid,sizeof, oderalignofOperator angewendet auf TypT; -
Arithmetischer Operator
angewendet auf einen Zeiger auf
T; -
Definition einer Klasse mit Basisklasse
T; -
Zuweisung an einen Lvalue vom Typ
T; -
ein
Handler
vom Typ
T, T & , oder T * .
(Im Allgemeinen, wenn die Größe und das Layout von
T
bekannt sein müssen.)
Wenn eine dieser Situationen in einer Übersetzungseinheit auftritt, muss die Definition des Typs in derselben Übersetzungseinheit erscheinen. Andernfalls ist sie nicht erforderlich.
Ein unvollständig definierter Objekttyp kann vervollständigt werden:
- Ein Klassentyp (wie class X ) kann an einer Stelle einer Übersetzungseinheit als unvollständig betrachtet werden und später als vollständig; der Typ class X ist an beiden Stellen derselbe Typ:
struct X; // Deklaration von X, noch keine Definition vorhanden extern X* xp; // xp ist ein Zeiger auf einen unvollständigen Typ: // die Definition von X ist nicht erreichbar void foo() { xp++; // fehlerhaft: X ist unvollständig } struct X { int i; }; // Definition von X X x; // OK: die Definition von X ist erreichbar void bar() { xp = &x; // OK: Typ ist "Zeiger auf X" xp++; // OK: X ist vollständig }
- Der deklarierte Typ eines Array-Objekts könnte ein Array von unvollständigem Klassentyp sein und daher unvollständig; wenn der Klassentyp später in der Übersetzungseinheit vervollständigt wird, wird der Array-Typ vollständig; der Array-Typ an diesen beiden Punkten ist derselbe Typ.
-
Der deklarierte Typ eines Array-Objekts könnte ein Array mit unbekannter Grenze sein und daher an einem Punkt in einer Übersetzungseinheit unvollständig und später vollständig sein; die Array-Typen an diesen beiden Punkten ("Array mit unbekannter Grenze von
T" und "Array von NT") sind unterschiedliche Typen.
Der Typ eines Zeigers oder einer Referenz auf ein Array unbekannter Größe zeigt permanent auf oder bezieht sich permanent auf einen unvollständigen Typ. Ein Array unbekannter Größe, das durch eine
typedef
-Deklaration benannt wird, bezieht sich permanent auf einen unvollständigen Typ. In beiden Fällen kann der Array-Typ nicht vervollständigt werden:
extern int arr[]; // der Typ von arr ist unvollständig typedef int UNKA[]; // UNKA ist ein unvollständiger Typ UNKA* arrp; // arrp ist ein Zeiger auf einen unvollständigen Typ UNKA** arrpp; void foo() { arrp++; // Fehler: UNKA ist ein unvollständiger Typ arrpp++; // OK: sizeof UNKA* ist bekannt } int arr[10]; // jetzt ist der Typ von arr vollständig void bar() { arrp = &arr; // OK: Qualifikationskonvertierung (seit C++20) arrp++; // Fehler: UNKA kann nicht vervollständigt werden }
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| CWG 328 | C++98 |
Klassenmitglieder von unvollständigem Typ waren nicht verboten
falls ein Objekt des Klassentyps nie erzeugt wurde |
nicht-statische Klassendatenmitglieder
müssen vollständig sein |
| CWG 977 | C++98 |
der Zeitpunkt, zu dem ein Aufzählungstyp in seiner Definition
vollständig wird, war unklar |
der Typ ist vollständig, sobald der
zugrundeliegende Typ bestimmt ist |
| CWG 1362 | C++98 |
benutzerdefinierte Konvertierungen zu Typ
T*
oder
T&
erforderten
T
vollständig
|
nicht erforderlich |
| CWG 2006 | C++98 | cv-qualifizierte void Typen waren Objekttyp und vollständiger Typ | von beiden Kategorien ausgeschlossen |
| CWG 2448 | C++98 | nur cv-unqualifizierte Typen konnten Integral- und Gleitkommatypen sein | erlaubt cv-qualifizierte Typen |
| CWG 2630 | C++98 |
es war unklar, ob eine Klasse außerhalb
der Übersetzungseinheit, in der die Definition der Klasse erscheint, als vollständig gilt |
die Klasse ist vollständig
wenn ihre Definition in diesem Fall erreichbar ist |
| CWG 2643 | C++98 |
der Typ eines Zeigers auf Array unbekannter Größe
konnte nicht vervollständigt werden (aber er ist bereits vollständig) |
der gezeigte Array-Typ
kann nicht vervollständigt werden |
| LWG 2139 | C++98 | die Bedeutung von "benutzerdefiniertem Typ" war unklar |
definiert und verwendet "programm-
definierter Typ" stattdessen |
| LWG 3119 | C++11 | es war unklar, ob Closure-Typen programm-definierte Typen sind | klargestellt |
Referenzen
- C++23-Standard (ISO/IEC 14882:2024):
-
- 6.8.2 Fundamentale Typen [basic.fundamental]
- C++20-Standard (ISO/IEC 14882:2020):
-
- 6.8.2 Fundamentale Typen [basic.fundamental]
- C++17-Standard (ISO/IEC 14882:2017):
-
- 6.9.1 Fundamentale Typen [basic.fundamental]
- C++14-Standard (ISO/IEC 14882:2014):
-
- 3.9.1 Fundamentale Typen [basic.fundamental]
- C++11-Standard (ISO/IEC 14882:2011):
-
- 3.9.1 Fundamentale Typen [basic.fundamental]
- C++98-Standard (ISO/IEC 14882:1998):
-
- 3.9.1 Fundamentale Typen [basic.fundamental]
Siehe auch
| Type traits | Eine template-basierte Schnittstelle zur Übersetzungszeit zum Abfragen der Eigenschaften von Typen |
|
C-Dokumentation
für
Typ
|
|
Externe Links
| 1. | Howard Hinnants C++0x Typenbaum |