Namespaces
Variants

User-defined conversion function

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

Ermöglicht implizite Konvertierung oder explizite Konvertierung von einem Klassentyp zu einem anderen Typ.

Inhaltsverzeichnis

Syntax

Konvertierungsfunktionen werden deklariert wie eine non-static member function oder eine function template ohne Parameter, ohne expliziten Rückgabetyp und mit einem Namen der Form:

operator conversion-type-id (1)
explicit operator conversion-type-id (2) (seit C++11)
explicit ( expression ) operator conversion-type-id (3) (seit C++20)
1) Deklariert eine benutzerdefinierte Konvertierungsfunktion, die an allen impliziten und expliziten Konvertierungen teilnimmt.
2) Deklariert eine benutzerdefinierte Konvertierungsfunktion, die nur an Direct-Initialization und expliziten Konvertierungen teilnimmt.
3) Deklariert eine benutzerdefinierte Konvertierungsfunktion, die bedingt explizit ist.

conversion-type-id ist ein type-id mit der Ausnahme, dass Funktions- und Array-Operatoren [] oder () in seinem Deklarator nicht erlaubt sind (daher erfordert die Konvertierung zu Typen wie Zeiger auf Array einen Typalias/typedef oder ein Identity-Template: siehe unten). Unabhängig von typedef kann conversion-type-id keinen Array- oder Funktionstyp repräsentieren.

Obwohl der Rückgabetyp in der Deklaration einer benutzerdefinierten Konvertierungsfunktion nicht erlaubt ist, kann die decl-specifier-seq der Deklarationsgrammatik vorhanden sein und darf jeden Spezifizierer außer type-specifier oder dem Schlüsselwort static enthalten. Insbesondere sind neben explicit auch die Spezifizierer inline , virtual , constexpr (seit C++11) , consteval (seit C++20) und friend erlaubt (beachten Sie, dass friend einen qualifizierten Namen erfordert: friend A :: operator B ( ) ; ).

Wenn eine solche Elementfunktion in der Klasse X deklariert wird, führt sie eine Konvertierung von X zu conversion-type-id durch:

struct X
{
    // implizite Konvertierung
    operator int() const { return 7; }
    // explizite Konvertierung
    explicit operator int*() const { return nullptr; }
    // Fehler: Array-Operator in Konvertierungstyp-ID nicht erlaubt
//  operator int(*)[3]() const { return nullptr; }
    using arr_t = int[3];
    operator arr_t*() const { return nullptr; } // OK wenn über Typedef durchgeführt
//  operator arr_t () const; // Fehler: Konvertierung zu Array in keinem Fall erlaubt
};
int main()
{
    X x;
    int n = static_cast<int>(x);   // OK: setzt n auf 7
    int m = x;                     // OK: setzt m auf 7
    int* p = static_cast<int*>(x); // OK: setzt p auf null
//  int* q = x; // Fehler: keine implizite Konvertierung
    int (*pa)[3] = x;  // OK
}

Erklärung

Die benutzerdefinierte Konvertierungsfunktion wird in der zweiten Stufe der impliziten Konvertierung aufgerufen, die aus null oder einem converting constructor oder null oder einer benutzerdefinierten Konvertierungsfunktion besteht.

Wenn sowohl Konvertierungsfunktionen als auch konvertierende Konstruktoren zur Durchführung einer benutzerdefinierten Konvertierung verwendet werden können, werden sowohl die Konvertierungsfunktionen als auch die Konstruktoren in Overload Resolution bei Copy-Initialization und Reference-Initialization Kontexten berücksichtigt, aber nur die Konstruktoren werden in Direct-Initialization Kontexten berücksichtigt.

struct To
{
    To() = default;
    To(const struct From&) {} // Konvertierungskonstruktor
};
struct From
{
    operator To() const {return To();} // Konvertierungsfunktion
};
int main()
{
    From f;
    To t1(f);  // Direktinitialisierung: ruft den Konstruktor auf
    // Hinweis: Falls kein Konvertierungskonstruktor verfügbar ist, wird der implizite Kopierkonstruktor
    // ausgewählt, und die Konvertierungsfunktion wird aufgerufen, um das Argument vorzubereiten
//  To t2 = f; // Kopierinitialisierung: mehrdeutig
    // Hinweis: Falls die Konvertierungsfunktion von einem nicht-konstanten Typ ist, z.B.
    // From::operator To();, wird sie in diesem Fall anstelle des Konstruktors ausgewählt
    To t3 = static_cast<To>(f); // Direktinitialisierung: ruft den Konstruktor auf
    const To& r = f;            // Referenzinitialisierung: mehrdeutig
}

Konvertierungsfunktion in die eigene (möglicherweise cv-qualifizierte) Klasse (oder in eine Referenz darauf), in die Basis der eigenen Klasse (oder in eine Referenz darauf) und in den Typ void kann definiert werden, kann aber nicht als Teil der Konvertierungssequenz ausgeführt werden, außer in einigen Fällen durch virtual dispatch:

struct D;
struct B
{
    virtual operator D() = 0;
};
struct D : B
{
    operator D() override { return D(); }
};
int main()
{
    D obj;
    D obj2 = obj; // ruft nicht D::operator D() auf
    B& br = obj;
    D obj3 = br;  // ruft D::operator D() durch virtuelle Auflösung auf
}

Es kann auch mit der Syntax für Member-Funktionsaufrufe aufgerufen werden:

struct B {};
struct X : B
{
    operator B&() { return *this; };
};
int main()
{
    X x;
    B& b1 = x;                  // ruft nicht X::operatorB&() auf
    B& b2 = static_cast<B&>(x); // ruft nicht X::operatorB& auf
    B& b3 = x.operator B&();    // ruft X::operatorB& auf
}

Beim expliziten Aufruf der Konvertierungsfunktion ist conversion-type-id gierig: Es ist die längste Sequenz von Tokens, die möglicherweise eine conversion-type-id bilden könnte (einschließlich Attribute, falls vorhanden) (seit C++11) :

& x.operator int * a; // Fehler: wird geparst als & (x.operator int*) a,
                      //           nicht als & (x.operator int) * a
operator int [[noreturn]] (); // Fehler: noreturn-Attribut auf einen Typ angewendet

Der Platzhalter auto kann in conversion-type-id verwendet werden, um einen abgeleiteten Rückgabetyp anzugeben:

struct X
{
    operator int(); // OK
    operator auto() -> short; // error: trailing return type not part of syntax
    operator auto() const { return 10; } // OK: deduced return type
    operator decltype(auto)() const { return 10l; } // OK: deduced return type
};

Hinweis: Eine Konvertierungsfunktionsvorlage darf keinen abgeleiteten Rückgabetyp haben.

(seit C++14)

Konvertierungsfunktionen können vererbt werden und können virtual sein, aber können nicht static sein. Eine Konvertierungsfunktion in der abgeleiteten Klasse verdeckt keine Konvertierungsfunktion in der Basisklasse, es sei denn, sie konvertieren in denselben Typ.

Konvertierungsfunktionen können Template-Memberfunktionen sein, zum Beispiel std::auto_ptr<T>::operator auto_ptr<Y> . Siehe Member-Templates und Template-Argument-Deduktion für die entsprechenden Sonderregeln.

Schlüsselwörter

operator

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 296 C++98 Konvertierungsfunktionen konnten static sein sie können nicht als static deklariert werden
CWG 2016 C++98 Konvertierungsfunktionen konnten keine Rückgabetypen angeben,
aber die Typen sind in conversion-type-id vorhanden
Rückgabetypen können nicht in den
Deklarationsspezifizierern von Konvertierungsfunktionen angegeben werden
CWG 2175 C++11 es war unklar, ob das [ [ noreturn ] ] in
operator int [ [ noreturn ] ] ( ) ; als Teil von
noptr-declarator (von Funktionsdeklarator) oder conversion-type-id geparst wird
es wird als Teil von
conversion-type-id geparst