Namensräume
Varianten
Aktionen

Explizite Typumwandlung

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Explizite Konvertierungen
dynamic_cast
reinterpret_cast
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

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.

1) Explizite Typumwandlung (Cast-Notation), auch C-Style-Cast genannt.
2-7) Explizite Typumwandlung (funktionale Notation), auch Funktions-Style-Cast genannt.
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

1) Wenn der C-Style-Cast angetroffen wird, versucht der Compiler, ihn in dieser Reihenfolge als die folgenden Cast-Ausdrücke zu interpretieren:
a) const_cast<typ-id >(unary-expression );
b) 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;
c) ein static_cast (mit Erweiterungen) gefolgt von const_cast;
d) reinterpret_cast<typ-id >(unary-expression );
e) ein reinterpret_cast gefolgt von const_cast.
Die erste Wahl, die die Anforderungen des jeweiligen Cast-Operators erfüllt, wird ausgewählt, auch wenn sie fehlerhaft ist (siehe Beispiel). Wenn ein static_cast gefolgt von einem const_cast verwendet wird und die Umwandlung auf mehr als eine Weise als solche interpretiert werden kann, ist die Umwandlung fehlerhaft.
Zusätzlich können C-Style-Casts von, zu und zwischen Zeigern auf unvollständige Klassentypen umwandeln. Wenn sowohl typ-id als auch der Typ von unary-expression Zeiger auf unvollständige Klassentypen sind, ist es undefiniert, ob static_cast oder reinterpret_cast ausgewählt wird.
2-7) Ein funktionsähnlicher Cast gibt einen **Typ** (simple-type-specifier oder identifier (seit C++11)) und einen **Initialisierer** (die restlichen Teile) an. Er konstruiert einen Wert des Zieltyps T, der aus dem angegebenen Typund Initialisierer(seit C++17) bestimmt wird.

T ist der angegebene Typ.

(bis C++17)

T wird wie folgt bestimmt:

  • Wenn der angegebene Typ ein Platzhalter für einen abgeleiteten Klassentyp ist, ist T der Rückgabetyp der Funktion, die durch Überladungsauflösung für Klassentempelatdeduktion ausgewählt wurde.
  • Andernfalls, wenn der angegebene Typ einen Platzhaltertyp enthält, ist T der abgeleitete Typ.
(seit C++23)
  • Andernfalls ist T der angegebene Typ.
(seit C++17)
Das Konvertierungsergebnis wird wie folgt bestimmt:
  • 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.
  • Wenn der Initialisierer nicht () ist, ist das Programm fehlerhaft.
(bis C++11)
  • Wenn der Initialisierer nach einer Pack Expansion (falls vorhanden) nicht () oder {} ist, ist das Programm fehlerhaft.
(seit C++11)
  • Andernfalls, wenn T ein Referenztyp ist, hat der funktionsähnliche Cast die gleiche Auswirkung wie das direkte Initialisieren einer erfundenen Variablen t vom Typ T aus dem angegebenen Initialisierer, und das Ergebnis ist die initialisierte t.
  • Das Ergebnis ist ein lvalue.
(bis C++11)
  • Wenn T ein lvalue-Referenztyp oder ein rvalue-Referenztyp auf eine Funktion ist, ist das Ergebnis ein lvalue.
  • Andernfalls ist das Ergebnis ein xvalue.
(seit C++11)
  • Andernfalls ist das Ergebnis ein rvalue(bis C++11)ein prvalue(seit C++11) vom Typ T das 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[bearbeiten]
static_cast-Konvertierung führt grundlegende Konvertierungen durch[bearbeiten]
dynamic_cast-Konvertierung führt überprüfte polymorphe Konvertierungen durch[bearbeiten]
reinterpret_cast-Konvertierung führt allgemeine Low-Level-Konvertierungen durch[bearbeiten]
Standardkonvertierungen implizite Konvertierungen von einem Typ zu einem anderen[bearbeiten]
C-Dokumentation für Cast-Operator