User-defined conversion function
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) | |||||||
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
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 |