Namespaces
Variants

Explicit type conversion

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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.

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

1) Wenn die C-Stil-Umwandlung angetroffen wird, versucht der Compiler, sie in der folgenden Reihenfolge als die folgenden Umwandlungsausdrücke zu interpretieren:
a) const_cast < type-id  > ( unary-expression  ) ;
b) 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;
c) a static_cast (mit Erweiterungen) gefolgt von const_cast ;
d) reinterpret_cast < Typ-ID  > ( unärer Ausdruck  ) ;
e) a reinterpret_cast gefolgt von const_cast .
Die erste Wahl, die den Anforderungen des jeweiligen Cast-Operators entspricht, wird ausgewählt, selbst wenn sie fehlerhaft ist (siehe Beispiel). Wenn ein static_cast gefolgt von einem const_cast verwendet wird und die Konvertierung auf mehr als eine Weise interpretiert werden kann, ist die Konvertierung fehlerhaft.
Darüber hinaus können C-style casts von, zu und zwischen Zeigern auf unvollständige Klassentypen umwandeln. Wenn sowohl type-id als auch der Typ von unary-expression Zeiger auf unvollständige Klassentypen sind, ist nicht spezifiziert, ob static_cast oder reinterpret_cast ausgewählt wird.
2-7) Ein Funktions-Stil-Cast spezifiziert einen Typ ( simple-type-specifier  oder identifier  (seit C++11) ) und einen Initialisierer (die verbleibenden Teile), er konstruiert einen Wert des Zieltyps T , der aus dem spezifizierten Typ und Initialisierer bestimmt wird (seit C++17) :

T ist der spezifizierte Typ.

(bis C++17)

T wird wie folgt bestimmt:

  • Wenn der spezifizierte Typ ein Platzhalter für einen deduzierten Klassentyp ist, T der Rückgabetyp der durch Overload-Resolution ausgewählten Funktion für Class Template Argument Deduction .
  • Andernfalls, wenn der spezifizierte Typ einen Platzhaltertyp enthält, T der deduzierte Typ.
(seit C++23)
  • Andernfalls ist T der spezifizierte Typ.
(seit C++17)
Das Konvertierungsergebnis wird wie folgt bestimmt:
  • 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.
  • Wenn der Initializer nicht ( ) ist, ist das Programm fehlerhaft.
(bis C++11)
  • Wenn der Initializer nach Pack-Expansion (falls vorhanden) nicht ( ) oder { } ist, ist das Programm fehlerhaft.
(seit C++11)
  • Andernfalls, wenn T ein Referenztyp ist, hat der funktionsartige Cast denselben Effekt wie die Direktinitialisierung einer erfundenen Variable t vom Typ T mit dem angegebenen Initializer, und das Ergebnis ist das initialisierte t .
  • Das Ergebnis ist ein Lvalue.
(bis C++11)
  • Wenn T ein Lvalue-Referenztyp oder eine Rvalue-Referenz auf einen Funktionstyp 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ä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