Explicit type conversion
Konvertiert zwischen Typen unter Verwendung einer Kombination aus expliziten und impliziten Konvertierungen.
Inhaltsverzeichnis |
Syntax
(
Typ-ID
)
unärer Ausdruck
|
(1) | ||||||||
einfacher Typspezifizierer
(
Ausdrucksliste
(optional)
)
einfacher Typspezifizierer
(
Initialisiererliste
(optional)
)
|
(2) |
(bis C++11)
(seit C++11) |
|||||||
einfacher Typspezifizierer
{
Initialisiererliste
(optional)
}
|
(3) | (seit C++11) | |||||||
einfacher Typspezifizierer
{
Designierte-Initialisiererliste
}
|
(4) | (seit C++20) | |||||||
typename
Bezeichner
(
Initialisiererliste
(optional)
)
|
(5) | (seit C++11) | |||||||
typename
Bezeichner
{
Initialisiererliste
(optional)
}
|
(6) | (seit C++11) | |||||||
typename
Bezeichner
{
Designierte-Initialisiererliste
}
|
(7) | (seit C++20) | |||||||
Konvertiert explizit eine beliebige Anzahl von Werten zu einem Wert des Zieltyps.
| type-id | - | ein Typ-Bezeichner |
| unary-expression | - | ein unärer Ausdruck (dessen oberster Operator keine Priorität höher als die eines C-Stil-Casts hat) |
| simple-type-specifier | - | ein einfacher Typ-Spezifizierer |
| expression-list | - | eine durch Kommas getrennte Liste von Ausdrücken (außer nicht in Klammern gesetzten Komma-Ausdrücken ) |
| initializer-list | - | eine durch Kommas getrennte Liste von Initialisierer-Klauseln |
| designated-initializer-list | - | eine durch Kommas getrennte Liste von bezeichneten Initialisierer-Klauseln |
| identifier | - | ein (möglicherweise qualifizierter) Bezeichner (einschließlich Template-Bezeichnern ) |
Erklärung
const_cast
<
type-id
>
(
unary-expression
)
;
static_cast
<
type-id
>
(
unary-expression
)
, mit Erweiterungen: Zeiger oder Referenz auf eine
abgeleitete Klasse
darf zusätzlich in Zeiger oder Referenz auf eine eindeutige Basisklasse umgewandelt werden (und umgekehrt), selbst wenn die Basisklasse
unzugänglich
ist (das heißt, diese Umwandlung ignoriert die private Vererbungsspezifikation). Gleiches gilt für die Umwandlung von
Zeigern auf Elemente
in Zeiger auf Elemente einer eindeutigen nicht-virtuellen Basis;
reinterpret_cast
<
Typ-ID
>
(
unärer Ausdruck
)
;
T
, der aus dem spezifizierten Typ
und Initialisierer bestimmt wird
(seit C++17)
:
|
|
(bis C++17) | ||
|
|
(seit C++17) |
- Wenn der funktionsartige Cast die Syntax (2) hat und genau ein Ausdruck in Klammern steht, entspricht dieser Cast dem entsprechenden C-ähnlichen Cast.
-
Andernfalls, wenn
T(möglicherweise cv-qualifiziert) void ist, ist das Ergebnis ein Rvalue (bis C++11) ein Prvalue (seit C++11) vom Typ void , das keine Initialisierung durchführt.
|
(bis C++11) |
|
(seit C++11) |
-
Andernfalls, wenn
Tein Referenztyp ist, hat der funktionsartige Cast denselben Effekt wie die Direktinitialisierung einer erfundenen Variable t vom TypTmit dem angegebenen Initializer, und das Ergebnis ist das initialisierte t .
|
(bis C++11) |
|
(seit C++11) |
-
Andernfalls ist das Ergebnis
ein Rvalue
(bis C++11)
ein Prvalue
(seit C++11)
vom Typ
T, das ein Temporärobjekt bezeichnet (bis C++17) , dessen Ergebnisobjekt (seit C++17) mit dem angegebenen Initializer direktinitialisiert wird.
Auflösung von Mehrdeutigkeiten
Mehrdeutige Deklarationsanweisung
Im Falle einer Mehrdeutigkeit zwischen einem Ausdrucksstatement mit einem Funktions-ähnlichen Cast-Ausdruck als seinem äußersten linken Teilausdruck und einer Deklarationsanweisung wird die Mehrdeutigkeit dadurch aufgelöst, dass sie als Deklaration behandelt wird. Diese Disambiguierung ist rein syntaktisch: Sie berücksichtigt nicht die Bedeutung der in der Anweisung vorkommenden Namen, außer ob es sich um Typnamen handelt:
struct M {}; struct L { L(M&); }; M n; void f() { M(m); // Deklaration, äquivalent zu M m; L(n); // fehlerhafte Deklaration, äquivalent zu L n; L(l)(m); // immer noch eine Deklaration, äquivalent zu L l((m)); }
|
Wenn jedoch der äußerste Deklarator in der mehrdeutigen Deklarationsanweisung einen trailing return type hat, wird die Anweisung nur dann als Deklarationsanweisung behandelt, wenn der trailing return type mit auto beginnt: struct M; struct S { S* operator()(); int N; int M; void mem(S s) { auto(s)()->M; // expression (S::M hides ::M), invalid before C++23 } }; void f(S s) { { auto(s)()->N; // expression, invalid before C++23 auto(s)()->M; // function declaration, equivalent to M s(); } { S(s)()->N; // expression S(s)()->M; // expression } } |
(seit C++11) |
Mehrdeutiger Funktionsparameter
Die oben genannte Mehrdeutigkeit kann auch im Kontext einer Deklaration auftreten. In diesem Kontext besteht die Wahl zwischen einer Objektdeklaration mit einem Funktions-Stil-Cast als Initialisierer und einer Deklaration mit einem Funktionsdeklarator mit einem redundanten Satz von Klammern um einen Parameternamen. Die Auflösung besteht ebenfalls darin, jedes Konstrukt, wie die potenzielle Parameterdeklaration, das möglicherweise eine Deklaration sein könnte, als Deklaration zu betrachten:
struct S { S(int); }; void foo(double a) { S w(int(a)); // Funktionsdeklaration: hat einen Parameter `a` vom Typ int S x(int()); // Funktionsdeklaration: hat einen unbenannten Parameter vom Typ int(*)() // der von int() angepasst wurde // Wege zur Vermeidung von Mehrdeutigkeit: S y((int(a))); // Objektdeklaration: zusätzliches Klammernpaar S y((int)a); // Objektdeklaration: C-Stil Cast S z = int(a); // Objektdeklaration: keine Mehrdeutigkeit bei dieser Syntax }
|
Wenn jedoch der äußerste Deklarator in der mehrdeutigen Parameterdeklaration einen trailing return type hat, wird die Mehrdeutigkeit nur dann als Deklaration aufgelöst, wenn sie mit auto beginnt: typedef struct BB { int C[2]; } *B, C; void foo() { S a(B()->C); // Objektdeklaration: B()->C kann keinen Parameter deklarieren S b(auto()->C); // Funktionsdeklaration: hat einen unbenannten Parameter vom Typ C(*)() // der von C() angepasst wurde } |
(seit C++11) |
Mehrdeutige Typ-ID
Eine Mehrdeutigkeit kann durch die Ähnlichkeit zwischen einem funktionsartigen Cast und einem Typ-Bezeichner entstehen. Die Auflösung besteht darin, dass jedes Konstrukt, das in seinem syntaktischen Kontext möglicherweise ein Typ-Bezeichner sein könnte, als Typ-Bezeichner betrachtet wird:
// `int()` und `int(unsigned(a))` können beide als Typ-ID geparst werden: // `int()` repräsentiert eine Funktion, die int zurückgibt // und keine Argumente annimmt // `int(unsigned(a))` repräsentiert eine Funktion, die int zurückgibt // und ein Argument vom Typ unsigned annimmt void foo(signed char a) { sizeof(int()); // Typ-ID (fehlerhaft) sizeof(int(a)); // Ausdruck sizeof(int(unsigned(a))); // Typ-ID (fehlerhaft) (int()) + 1; // Typ-ID (fehlerhaft) (int(a)) + 1; // Ausdruck (int(unsigned(a))) + 1; // Typ-ID (fehlerhaft) }
|
Wenn jedoch der äußerste abstract-declarator in der mehrdeutigen type-id einen trailing return type hat, wird die Mehrdeutigkeit nur dann aufgelöst, indem sie als type-id behandelt wird, wenn sie mit auto beginnt: typedef struct BB { int C[2]; } *B, C; void foo() { sizeof(B()->C[1]); // OK, sizeof(expression) sizeof(auto()->C[1]); // error: sizeof of a function returning an array } |
(seit C++11) |
Hinweise
| Feature-Test-Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_auto_cast
|
202110L
|
(C++23) | auto ( x ) und auto { x } |
Beispiel
#include <cassert> #include <iostream> double f = 3.14; unsigned int n1 = (unsigned int)f; // C-Style-Cast unsigned int n2 = unsigned(f); // Funktions-Style-Cast class C1; class C2; C2* foo(C1* p) { return (C2*)p; // castet unvollständigen Typ zu unvollständigem Typ } void cpp23_decay_copy_demo() { auto inc_print = [](int& x, const int& y) { ++x; std::cout << "x:" << x << ", y:" << y << '\n'; }; int p{1}; inc_print(p, p); // gibt x:2 y:2 aus, weil Parameter y hier ein Alias von p ist int q{1}; inc_print(q, auto{q}); // gibt x:2 y:1 aus, auto{q} (C++23) castet zu Prvalue, // daher ist Parameter y eine Kopie von q (kein Alias von q) } // In diesem Beispiel wird C-Style-Cast als static_cast interpretiert // obwohl es als reinterpret_cast funktionieren würde struct A {}; struct I1 : A {}; struct I2 : A {}; struct D : I1, I2 {}; int main() { D* d = nullptr; // A* a = (A*)d; // Kompilierfehler A* a = reinterpret_cast<A*>(d); // dies kompiliert assert(a == nullptr); cpp23_decay_copy_demo(); }
Ausgabe:
x:2 y:2 x:2 y:1
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 1223
( P2915R0 ) |
C++11 | die Einführung des Trailing-Return-Typs führte zu mehr Mehrdeutigkeiten | löst diese auf |
| CWG 1893 | C++11 | Funktionsstil-Cast berücksichtigte keine Pack-Expansions | berücksichtigt diese |
| CWG 2351 | C++11 | void { } war fehlerhaft | als korrekt definiert |
| CWG 2620 | C++98 |
die Auflösung mehrdeutiger Funktionsparameter
könnte fehlinterpretiert werden |
verbesserte die Formulierung |
| CWG 2828 | C++98 |
ein C-Stil-Cast war fehlerhaft, wenn mehrere Interpretationen
eines static_cast gefolgt von einem const_cast existieren, unabhängig davon, ob diese Konvertierungen tatsächlich verwendet werden |
berücksichtigt nur die
Konvertierungen, die möglicherweise verwendet werden |
| CWG 2894 | C++98 | Funktionsstil-Casts konnten Referenz-Rvalues erzeugen | können nur Referenz-Lvalues erzeugen |
Referenzen
- C++23-Standard (ISO/IEC 14882:2024):
-
- 7.6.1.4 Explizite Typkonvertierung (funktionale Notation) [expr.type.conv]
-
- 7.6.3 Explizite Typkonvertierung (Cast-Notation) [expr.cast]
- C++20-Standard (ISO/IEC 14882:2020):
-
- 7.6.1.4 Explizite Typkonvertierung (funktionale Notation) [expr.type.conv]
-
- 7.6.3 Explizite Typkonvertierung (Cast-Notation) [expr.cast]
- C++17-Standard (ISO/IEC 14882:2017):
-
- 8.2.3 Explizite Typkonvertierung (funktionale Notation) [expr.type.conv]
-
- 8.4 Explizite Typkonvertierung (Cast-Notation) [expr.cast]
- C++14-Standard (ISO/IEC 14882:2014):
-
- 5.2.3 Explizite Typkonvertierung (funktionale Notation) [expr.type.conv]
-
- 5.4 Explizite Typkonvertierung (Cast-Notation) [expr.cast]
- C++11-Standard (ISO/IEC 14882:2011):
-
- 5.2.3 Explizite Typkonvertierung (funktionale Notation) [expr.type.conv]
-
- 5.4 Explizite Typkonvertierung (Cast-Notation) [expr.cast]
- C++03-Standard (ISO/IEC 14882:2003):
-
- 5.2.3 Explizite Typkonvertierung (funktionale Notation) [expr.type.conv]
-
- 5.4 Explizite Typkonvertierung (Cast-Notation) [expr.cast]
- C++98 Standard (ISO/IEC 14882:1998):
-
- 5.2.3 Explizite Typkonvertierung (funktionale Notation) [expr.type.conv]
-
- 5.4 Explizite Typkonvertierung (Cast-Notation) [expr.cast]
Siehe auch
const_cast
Konvertierung
|
fügt const hinzu oder entfernt es |
static_cast
Konvertierung
|
führt grundlegende Konvertierungen durch |
dynamic_cast
Konvertierung
|
führt geprüfte polymorphe Konvertierungen durch |
reinterpret_cast
Konvertierung
|
führt allgemeine Low-Level-Konvertierungen durch |
| Standardkonvertierungen | implizite Konvertierungen von einem Typ zu einem anderen |
|
C-Dokumentation
für
Cast-Operator
|
|