Explizite Typumwandlung
Wandelt zwischen Typen unter Verwendung einer Kombination aus expliziten und impliziten Umwandlungen um.
Inhalt |
[bearbeiten] Syntax
( typ-id ) unary-expression |
(1) | ||||||||
simple-type-specifier ( expression-list (optional) )simple-type-specifier ( initializer-list (optional) ) |
(2) | (bis C++11) (seit C++11) | |||||||
simple-type-specifier { initializer-list (optional) } |
(3) | (seit C++11) | |||||||
simple-type-specifier { designated-initializer-list } |
(4) | (seit C++20) | |||||||
typename identifier ( initializer-list (optional) ) |
(5) | (seit C++11) | |||||||
typename identifier { initializer-list (optional) } |
(6) | (seit C++11) | |||||||
typename identifier { designated-initializer-list } |
(7) | (seit C++20) | |||||||
Konvertiert explizit eine beliebige Anzahl von Werten in einen Wert des Zieltyps.
| type-id | - | a Typ-ID |
| Unary-Ausdruck | - | ein Unary-Ausdruck (dessen oberster Operator keine Priorität hat, die höher ist als die von C-Style-Cast) |
| einfacher Typ-Spezifizierer | - | ein einfacher Typ-Spezifizierer |
| Ausdrucksliste | - | eine durch Kommas getrennte Liste von Ausdrücken (außer nicht geklammerten Komma-Ausdrücken) |
| Initialisiererliste | - | eine durch Kommas getrennte Liste von Initialisierer-Klauseln |
| Designated-Initialisierer-Liste | - | eine durch Kommas getrennte Liste von Designated-Initialisierer-Klauseln |
| identifier | - | ein (möglicherweise qualifizierter) Bezeichner (einschließlich Template-Bezeichnern) |
[bearbeiten] Erklärung
const_cast<typ-id >(unary-expression );static_cast<typ-id >(unary-expression ), mit Erweiterungen: Zeiger oder Referenz auf eine abgeleitete Klasse darf zusätzlich in Zeiger oder Referenz auf eine eindeutige Basisklasse (und umgekehrt) umgewandelt werden, auch wenn die Basisklasse unzugänglich ist (d. h. dieser Cast ignoriert den privaten Vererbungsspezifizierer). Dasselbe gilt für die Umwandlung von Zeigern auf Member in Zeiger auf Member einer eindeutigen nicht-virtuellen Basis;reinterpret_cast<typ-id >(unary-expression );T, der aus dem angegebenen Typund Initialisierer(seit C++17) bestimmt wird.|
|
(bis C++17) | ||
|
|
(seit C++17) |
- Wenn der funktionsähnliche Cast die Syntax (2) hat und genau ein Ausdruck in Klammern vorhanden ist, ist dieser Cast äquivalent zum entsprechenden C-Style-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, der keine Initialisierung durchführt.
|
(bis C++11) |
|
(seit C++11) |
- Andernfalls, wenn
Tein Referenztyp ist, hat der funktionsähnliche Cast die gleiche Auswirkung wie das direkte Initialisieren einer erfundenen Variablen t vom TypTaus dem angegebenen Initialisierer, und das Ergebnis ist die initialisierte t.
|
(bis C++11) |
|
(seit C++11) |
- Andernfalls ist das Ergebnis ein rvalue(bis C++11)ein prvalue(seit C++11) vom Typ
Tdas ein temporäres Objekt bezeichnet(bis C++17)dessen Ergebnisobjekt(seit C++17) direkt initialisiert ist mit dem angegebenen Initialisierer.
[bearbeiten] Auflösung von Mehrdeutigkeiten
[bearbeiten] Mehrdeutige Deklarationsanweisung
Im Falle einer Mehrdeutigkeit zwischen einer Ausdrucksanweisung mit einem funktionsähnlichen Cast-Ausdruck als ihrem am weitesten links stehenden Teil-Ausdruck und einer Deklarationsanweisung wird die Mehrdeutigkeit durch Behandlung als Deklaration aufgelöst. Diese Disambiguierung ist rein syntaktisch: sie berücksichtigt nicht die Bedeutung von Namen, die in der Anweisung vorkommen, außer ob es sich um Typnamen handelt.
struct M {}; struct L { L(M&); }; M n; void f() { M(m); // declaration, equivalent to M m; L(n); // ill-formed declaration, equivalent to L n; L(l)(m); // still a declaration, equivalent to L l((m)); }
|
Wenn jedoch der äußerste Deklarator in der mehrdeutigen Deklarationsanweisung einen nachgestellten Rückgabetyp hat, wird die Anweisung nur dann als Deklarationsanweisung behandelt, wenn der nachgestellte Rückgabetyp 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) |
[bearbeiten] Mehrdeutiger Funktionsparameter
Die obige Mehrdeutigkeit kann auch im Kontext einer Deklaration auftreten. In diesem Kontext besteht die Wahl zwischen einer Objektdeklaration mit einem funktionsähnlichen Cast als Initialisierer und einer Deklaration, die einen Funktionsdeklarator mit einem redundanten Satz von Klammern um einen Parameternamen beinhaltet. Die Auflösung besteht darin, jedes Konstrukt, das möglicherweise eine Deklaration sein könnte, als Deklaration zu betrachten.
struct S { S(int); }; void foo(double a) { S w(int(a)); // function declaration: has a parameter `a` of type int S x(int()); // function declaration: has an unnamed parameter of type int(*)() // that is adjusted from int() // Ways to avoid ambiguity: S y((int(a))); // object declaration: extra pair of parentheses S y((int)a); // object declaration: C-style cast S z = int(a); // object declaration: no ambiguity for this syntax }
|
Wenn jedoch der äußerste Deklarator in der mehrdeutigen Parameterdeklaration einen nachgestellten Rückgabetyp 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); // object declaration: B()->C cannot declare a parameter S b(auto()->C); // function declaration: has an unnamed parameter of type C(*)() // that is adjusted from C() } |
(seit C++11) |
[bearbeiten] Mehrdeutige Typ-ID
Eine Mehrdeutigkeit kann aus der Ähnlichkeit zwischen einem funktionsähnlichen Cast und einer Typ-ID entstehen. Die Auflösung besteht darin, dass jedes Konstrukt, das in seinem syntaktischen Kontext eine Typ-ID sein könnte, als Typ-ID betrachtet wird.
// `int()` and `int(unsigned(a))` can both be parsed as type-id: // `int()` represents a function returning int // and taking no argument // `int(unsigned(a))` represents a function returning int // and taking an argument of type unsigned void foo(signed char a) { sizeof(int()); // type-id (ill-formed) sizeof(int(a)); // expression sizeof(int(unsigned(a))); // type-id (ill-formed) (int()) + 1; // type-id (ill-formed) (int(a)) + 1; // expression (int(unsigned(a))) + 1; // type-id (ill-formed) }
|
Wenn jedoch der äußerste abstract-declarator in der mehrdeutigen Typ-ID einen nachgestellten Rückgabetyp hat, wird die Mehrdeutigkeit nur dann als Typ-ID aufgelöst, 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) |
[bearbeiten] Anmerkungen
| Feature-Testmakro | Wert | Std | Feature |
|---|---|---|---|
__cpp_auto_cast |
202110L |
(C++23) | auto(x) und auto{x} |
[bearbeiten] Beispiel
#include <cassert> #include <iostream> double f = 3.14; unsigned int n1 = (unsigned int)f; // C-style cast unsigned int n2 = unsigned(f); // function-style cast class C1; class C2; C2* foo(C1* p) { return (C2*)p; // casts incomplete type to incomplete type } 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); // prints x:2 y:2, because param y here is an alias of p int q{1}; inc_print(q, auto{q}); // prints x:2 y:1, auto{q} (C++23) casts to prvalue, // so the param y is a copy of q (not an alias of q) } // In this example, C-style cast is interpreted as static_cast // even though it would work as reinterpret_cast struct A {}; struct I1 : A {}; struct I2 : A {}; struct D : I1, I2 {}; int main() { D* d = nullptr; // A* a = (A*)d; // compile-time error A* a = reinterpret_cast<A*>(d); // this compiles assert(a == nullptr); cpp23_decay_copy_demo(); }
Ausgabe
x:2 y:2 x:2 y:1
[bearbeiten] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 1223 (P2915R0) |
C++11 | die Hinzufügung von nachgestellten Rückgabetypen führte zu mehr Mehrdeutigkeiten | löst sie auf |
| CWG 1893 | C++11 | funktionsähnliche Casts berücksichtigten keine Pack Expansions | berücksichtigt sie |
| CWG 2351 | C++11 | void{} war fehlerhaft | wurde wohlgeformt gemacht |
| CWG 2620 | C++98 | die Auflösung mehrdeutiger Funktionen Parameter könnten falsch interpretiert werden |
verbesserte die Formulierung |
| CWG 2828 | C++98 | ein C-Style-Cast war fehlerhaft, wenn mehrere Interpretationen eines static_cast gefolgt von einem const_cast existierten, unabhängig davon, ob diese Konvertierungen tatsächlich verwendet werden |
berücksichtigt nur die Konvertierungen möglicherweise verwendet werdenden |
| CWG 2894 | C++98 | funktionsähnliche Casts konnten Referenz-rvalues erstellen | können nur Referenz-lvalues erstellen |
[bearbeiten] Referenzen
- C++23 Standard (ISO/IEC 14882:2024)
- 7.6.1.4 Explizite Typumwandlung (funktionale Notation) [expr.type.conv]
- 7.6.3 Explizite Typumwandlung (Cast-Notation) [expr.cast]
- C++20 Standard (ISO/IEC 14882:2020)
- 7.6.1.4 Explizite Typumwandlung (funktionale Notation) [expr.type.conv]
- 7.6.3 Explizite Typumwandlung (Cast-Notation) [expr.cast]
- C++17 Standard (ISO/IEC 14882:2017)
- 8.2.3 Explizite Typumwandlung (funktionale Notation) [expr.type.conv]
- 8.4 Explizite Typumwandlung (Cast-Notation) [expr.cast]
- C++14 Standard (ISO/IEC 14882:2014)
- 5.2.3 Explizite Typumwandlung (funktionale Notation) [expr.type.conv]
- 5.4 Explizite Typumwandlung (Cast-Notation) [expr.cast]
- C++11 Standard (ISO/IEC 14882:2011)
- 5.2.3 Explizite Typumwandlung (funktionale Notation) [expr.type.conv]
- 5.4 Explizite Typumwandlung (Cast-Notation) [expr.cast]
- C++03-Standard (ISO/IEC 14882:2003)
- 5.2.3 Explizite Typumwandlung (funktionale Notation) [expr.type.conv]
- 5.4 Explizite Typumwandlung (Cast-Notation) [expr.cast]
- C++98 Standard (ISO/IEC 14882:1998)
- 5.2.3 Explizite Typumwandlung (funktionale Notation) [expr.type.conv]
- 5.4 Explizite Typumwandlung (Cast-Notation) [expr.cast]
[bearbeiten] 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 überprü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
| |