Overload resolution
Um einen Funktionsaufruf zu kompilieren, muss der Compiler zunächst Namenssuche durchführen, was bei Funktionen argumentabhängige Suche beinhalten kann, und bei Funktions-Templates gefolgt werden kann von Template-Argument-Ableitung .
Wenn der Name sich auf mehr als eine Entität bezieht, wird er als überladen bezeichnet, und der Compiler muss bestimmen, welche Überladung aufgerufen werden soll. Einfach ausgedrückt ist die Überladung, deren Parameter den Argumenten am besten entsprechen, diejenige, die aufgerufen wird.
Im Detail verläuft die Überladungsauflösung durch die folgenden Schritte:
- Erstellen der Menge der Kandidatenfunktionen .
- Reduzieren der Menge auf nur geeignete Funktionen .
- Analyse der Menge zur Bestimmung der einzelnen besten geeigneten Funktion (dies kann Rangfolge von impliziten Konvertierungssequenzen beinhalten).
void f(long); void f(float); f(0L); // ruft f(long) auf f(0); // Fehler: mehrdeutige Überladung
Neben Funktionsaufrufen können überladene Funktionsnamen in mehreren weiteren Kontexten auftreten, in denen unterschiedliche Regeln gelten: siehe Adresse einer überladenen Funktion .
Wenn eine Funktion durch Überladungsauflösung nicht ausgewählt werden kann, kann sie nicht verwendet werden (z.B. handelt es sich um eine templated entity mit einer fehlgeschlagenen constraint ).
Kandidatenfunktionen
Vor dem Beginn der Überlagerungsauflösung werden die durch Namenssuche und Template-Argumentableitung ausgewählten Funktionen kombiniert, um die Menge der Kandidatenfunktionen zu bilden. Die genauen Details hängen vom Kontext ab, in dem die Überlagerungsauflösung stattfinden wird.
Aufruf einer benannten Funktion
Wenn E in einem Funktionsaufrufausdruck E ( args ) eine Menge überladener Funktionen und/oder Funktionsvorlagen (aber keine aufrufbaren Objekte) benennt, werden die folgenden Regeln befolgt:
-
Wenn der Ausdruck
E
die Form
PA
-
>
B
oder
A.
B
hat (wobei
A
den Klassentyp
cv
Tbesitzt), dann wird B als Memberfunktion vonTgesucht. Die durch diese Suche gefundenen Funktionsdeklarationen sind die Kandidatenfunktionen. Die Argumentliste für die Überlagerungsauflösung enthält das implizite Objektargument vom Typ cvT. - Wenn der Ausdruck E ein Primärausdruck ist, wird der Name gemäß den normalen Regeln für Funktionsaufrufe gesucht (was ADL einschließen kann). Die durch diese Suche gefundenen Funktionsdeklarationen sind (aufgrund der Funktionsweise der Suche) entweder:
-
- alle Nicht-Mitgliedsfunktionen (in diesem Fall ist die Argumentliste für den Zweck der Überladungsauflösung genau die im Funktionsaufrufausdruck verwendete Argumentliste)
-
alle Mitgliedsfunktionen einer Klasse
T, in welchem Fall, wenn this im Gültigkeitsbereich ist und aufToder eine abgeleitete Klasse vonTzeigt, * this als implizites Objektargument verwendet wird. Andernfalls (wenn this nicht im Gültigkeitsbereich ist oder nicht aufTzeigt), wird ein Pseudo-Objekt vom TypTals implizites Objektargument verwendet, und wenn die Überladungsauflösung anschließend eine nicht-statische Mitgliedsfunktion auswählt, ist das Programm fehlerhaft.
Aufruf eines Klassenobjekts
Wenn
E
in einem
Funktionsaufrufausdruck
E
(
args
)
den Klassentyp
cv
T
hat, dann
-
Die Funktionsaufrufoperatoren von
Twerden durch gewöhnliche Namenssuche des Namens operator ( ) im Kontext des Ausdrucks ( E ) . operator ( ) ermittelt, und jede gefundene Deklaration wird zur Menge der Kandidatenfunktionen hinzugefügt. -
Für jede nicht-
explicitbenutzerdefinierte Konvertierungsfunktion inToder in einer Basisklasse vonT(sofern nicht verborgen), deren CV-Qualifizierer gleich oder stärker als die CV-Qualifizierer vonTsind, und bei der die Konvertierungsfunktion konvertiert zu:
-
- pointer-to-function
- reference-to-pointer-to-function
- reference-to-function
- dann wird eine Ersatzaufruffunktion mit einem eindeutigen Namen, deren erster Parameter das Ergebnis der Konvertierung ist, die restlichen Parameter die vom Ergebnis der Konvertierung akzeptierte Parameterliste sind und deren Rückgabetyp der Rückgabetyp des Ergebnisses der Konvertierung ist, zur Menge der Kandidatenfunktionen hinzugefügt. Wenn diese Ersatzfunktion durch die nachfolgende Überladungsauflösung ausgewählt wird, dann wird die benutzerdefinierte Konvertierungsfunktion aufgerufen und anschließend wird das Ergebnis der Konvertierung aufgerufen.
In jedem Fall ist die Argumentliste für den Zweck der Überladungsauflösung die Argumentliste des Funktionsaufrufausdrucks, dem das implizite Objektargument E vorangestellt ist (bei der Übereinstimmung mit der Ersatzfunktion wird die benutzerdefinierte Konvertierung das implizite Objektargument automatisch in das erste Argument der Ersatzfunktion konvertieren).
int f1(int); int f2(float); struct A { using fp1 = int(*)(int); operator fp1() { return f1; } // Konvertierungsfunktion zu Zeiger auf Funktion using fp2 = int(*)(float); operator fp2() { return f2; } // Konvertierungsfunktion zu Zeiger auf Funktion } a; int i = a(1); // ruft f1 über den von der Konvertierungsfunktion zurückgegebenen Zeiger auf
Aufruf eines überladenen Operators
Wenn mindestens eines der Argumente eines Operators in einem Ausdruck einen Klassentyp oder einen Aufzählungstyp hat, nehmen sowohl integrierte Operatoren als auch benutzerdefinierte Operatorüberladungen an der Überladungsauflösung teil, wobei der Satz an Kandidatenfunktionen wie folgt ausgewählt wird:
Für einen unären Operator
@
dessen Argument den Typ
T1
hat (nach Entfernen von CV-Qualifizierern), oder einen binären Operator
@
dessen linker Operand den Typ
T1
hat und rechter Operand den Typ
T2
(nach Entfernen von CV-Qualifizierern), werden die folgenden Mengen an Kandidatenfunktionen bereitgestellt:
T1
eine vollständige Klasse oder eine aktuell definierte Klasse ist, dann ist die Menge der Mitgliederkandidaten das Ergebnis der
qualifizierten Namenssuche
von
T1::operator@
. In allen anderen Fällen ist die Menge der Mitgliederkandidaten leer.
operator@
im Kontext des Ausdrucks gefunden werden (was
ADL
beinhalten kann), mit der Ausnahme, dass Member-Funktionsdeklarationen ignoriert werden und die Suche nicht daran hindern, im nächsten einschließenden Gültigkeitsbereich fortzufahren. Wenn beide Operanden eines binären Operators oder der einzige Operand eines unären Operators einen Aufzählungstyp haben, sind die einzigen Funktionen aus der Suchmenge, die zu Nicht-Member-Kandidaten werden, diejenigen, deren Parameter diesen Aufzählungstyp (oder Referenz auf diesen Aufzählungstyp) hat.
|
4)
umgeschriebene Kandidaten
:
In allen Fällen werden umgeschriebene Kandidaten nicht im Kontext des umgeschriebenen Ausdrucks betrachtet. Für alle anderen Operatoren ist die Menge der umgeschriebenen Kandidaten leer.
|
(seit C++20) |
Die Menge der Kandidatenfunktionen, die für die Überladungsauflösung eingereicht werden, ist eine Vereinigung der oben genannten Mengen. Die Argumentliste für die Zwecke der Überladungsauflösung besteht aus den Operanden des Operators, mit Ausnahme von
operator->
, bei dem der zweite Operand kein Argument für den Funktionsaufruf ist (siehe
member access operator
).
struct A { operator int(); // benutzerdefinierte Konvertierung }; A operator+(const A&, const A&); // nicht-Mitglied benutzerdefinierter Operator void m() { A a, b; a + b; // Mitglied-Kandidaten: keine // Nicht-Mitglied-Kandidaten: operator+(a, b) // eingebaute Kandidaten: int(a) + int(b) // Überladungsauflösung wählt operator+(a, b) }
Wenn die Überladungsauflösung einen eingebauten Kandidaten auswählt, darf die benutzerdefinierte Konvertierungssequenz von einem Operanden eines Klassentyps keine zweite Standardkonvertierungssequenz enthalten: Die benutzerdefinierte Konvertierungsfunktion muss den erwarteten Operandentyp direkt liefern:
struct Y { operator int*(); }; // Y ist konvertierbar zu int* int *a = Y() + 100.0; // Fehler: kein operator+ zwischen Zeiger und double
Für operator, , den unären operator & , und operator - > , wenn es keine geeigneten Funktionen (siehe unten) in der Menge der Kandidatenfunktionen gibt, wird der Operator als eingebaut reinterpretiert.
|
Wenn ein umgeschriebener
operator
<=>
-Kandidat durch Überladungsauflösung für einen Operator
Wenn ein umgeschriebener
operator
==
-Kandidat durch Überladungsauflösung für einen Operator
Die Überladungsauflösung hat in diesem Fall einen finalen Tie-Breaker, der nicht-umgeschriebene Kandidaten gegenüber umgeschriebenen Kandidaten bevorzugt und nicht-synthetisierte umgeschriebene Kandidaten gegenüber synthetisierten umgeschriebenen Kandidaten bevorzugt. Diese Suche mit umgekehrter Argumentreihenfolge ermöglicht es, nur operator <=> ( std:: string , const char * ) und operator == ( std:: string , const char * ) zu schreiben, um alle Vergleiche zwischen std::string und const char * in beide Richtungen zu generieren. Siehe Standardvergleiche für weitere Details. |
(seit C++20) |
Initialisierung durch Konstruktor
Wenn ein Objekt vom Klassentyp direkt initialisiert oder standardmäßig initialisiert (einschließlich Standardinitialisierung im Kontext von Copy-List-Initialisierung ) (seit C++11) wird, sind die Kandidatenfunktionen alle Konstruktoren der zu initialisierenden Klasse. Die Argumentliste ist die Ausdrucksliste des Initialisierers.
Andernfalls sind die Kandidatenfunktionen alle converting constructors der zu initialisierenden Klasse. Die Argumentliste ist der Ausdruck des Initialisierers.
|
Für die Standardinitialisierung im Kontext der Copy-List-Initialisierung, falls ein
|
(since C++11) |
Copy-Initialisierung durch Konvertierung
Wenn die
Copy-Initialisierung
eines Objekts vom Klassentyp erfordert, dass eine benutzerdefinierte Konvertierung aufgerufen wird, um den Initialisierungsausdruck vom Typ
cv
S
in den Typ
cv
T
des zu initialisierenden Objekts zu konvertieren, sind die folgenden Funktionen Kandidatenfunktionen:
-
alle
converting constructors
von
T -
die nicht-
explicitKonvertierungsfunktionen vonSund seinen Basisklassen (sofern nicht verborgen) zuToder einer vonTabgeleiteten Klasse oder einer Referenz darauf. Wenn diese Kopierinitialisierung Teil der Direktinitialisierungssequenz von cvTist (Initialisierung einer Referenz, die an den ersten Parameter eines Konstruktors gebunden werden soll, der eine Referenz auf cvTnimmt), dann werden auch explizite Konvertierungsfunktionen berücksichtigt.
In jedem Fall besteht die Argumentliste für den Zweck der Überladungsauflösung aus einem einzelnen Argument, welches der Initialisierungsausdruck ist, der gegen das erste Argument des Konstruktors oder gegen das implizite Objektargument der Konvertierungsfunktion verglichen wird.
Initialisierung von Nicht-Klassen durch Konvertierung
Wenn die Initialisierung eines Objekts von Nicht-Klassentyp
cv1
T
eine
benutzerdefinierte Konvertierungsfunktion
erfordert, um von einem Initialisierungsausdruck des Klassentyps
cv
S
zu konvertieren, sind die folgenden Funktionen Kandidaten:
-
die nicht-expliziten benutzerdefinierten Konvertierungsfunktionen von
Sund seinen Basisklassen (sofern nicht verborgen), die TypToder einen durch eine Standardkonvertierungssequenz konvertierbaren Typ zuTerzeugen, oder eine Referenz auf einen solchen Typ. CV-Qualifizierer auf dem Rückgabetyp werden für die Auswahl der Kandidatenfunktionen ignoriert. -
falls es sich um
Direktinitialisierung
handelt, werden auch die expliziten benutzerdefinierten Konvertierungsfunktionen von
Sund seinen Basisklassen (sofern nicht verborgen) berücksichtigt, die TypToder einen durch eine Qualifikationskonvertierung konvertierbaren Typ zuTerzeugen, oder eine Referenz auf einen solchen Typ.
In jedem Fall besteht die Argumentliste für den Zweck der Überladungsauflösung aus einem einzelnen Argument, welches der Initialisierungsausdruck ist, der mit dem impliziten Objektargument der Konvertierungsfunktion verglichen wird.
Referenzinitialisierung durch Konvertierung
Während der
Referenzinitialisierung
, wenn die Referenz auf
cv1
T
an das Lvalue- oder Rvalue-Ergebnis einer Konvertierung vom Initialisierungsausdruck vom Klassentyp
cv2
S
gebunden wird, werden die folgenden Funktionen für den Kandidatensatz ausgewählt:
-
Die nicht-expliziten benutzerdefinierten Konvertierungsfunktionen von
Sund seiner Basisklassen (sofern nicht verborgen) zum Typ
-
-
(bei Konvertierung in einen Lvalue) Lvalue-Referenz auf
cv2
T2 -
(bei Konvertierung in einen Rvalue oder Lvalue vom Funktionstyp)
cv2
T2oder Rvalue-Referenz auf cv2T2
-
(bei Konvertierung in einen Lvalue) Lvalue-Referenz auf
cv2
-
wobei
cv2
T2referenzkompatibel mit cv1Tist.
-
Für die direkte Initialisierung werden auch explizite benutzerdefinierte Konvertierungsfunktionen berücksichtigt, wenn
T2denselben Typ wieTaufweist oder durch eine Qualifikationskonvertierung in den TypTumgewandelt werden kann.
In jedem Fall besteht die Argumentliste für den Zweck der Überladungsauflösung aus einem einzelnen Argument, welches der Initialisierungsausdruck ist, der mit dem impliziten Objektargument der Konvertierungsfunktion verglichen wird.
Listeninitialisierung
Wenn ein Objekt eines Nicht-Aggregat-Klassentyps
T
Listeninitialisierung
durchläuft, findet eine zweiphasige Überlagerungsauflösung statt.
-
In Phase 1 sind die Kandidatenfunktionen alle Initializer-List-Konstruktoren von
Tund die Argumentliste für die Überlagerungsauflösung besteht aus einem einzelnen Initializer-Listen-Argument -
Falls die Überlagerungsauflösung in Phase 1 fehlschlägt, wird Phase 2 eingeleitet, in der die Kandidatenfunktionen alle Konstruktoren von
Tsind und die Argumentliste für die Überlagerungsauflösung aus den einzelnen Elementen der Initializer-Liste besteht.
Wenn die Initialisiererliste leer ist und
T
einen Standardkonstruktor hat, wird Phase 1 übersprungen.
Bei der Copy-Listen-Initialisierung ist die Initialisierung fehlerhaft, wenn Phase 2 einen expliziten Konstruktor auswählt (im Gegensatz zu allen anderen Copy-Initialisierungen, bei denen explizite Konstruktoren nicht einmal berücksichtigt werden).
Zusätzliche Regeln für Funktions-Template-Kandidaten
Wenn die Namenssuche eine Funktionsvorlage findet, werden Template-Argument-Deduktion und die Überprüfung expliziter Template-Argumente durchgeführt, um die Template-Argumentwerte (falls vorhanden) zu ermitteln, die in diesem Fall verwendet werden können:
- Wenn beides erfolgreich ist, werden die Template-Argumente verwendet, um Deklarationen der entsprechenden Funktions-Template-Spezialisierungen zu synthetisieren, die zur Kandidatenmenge hinzugefügt werden, und solche Spezialisierungen werden wie Nicht-Template-Funktionen behandelt, außer wo in den nachfolgenden Tie-Breaker-Regeln anders angegeben.
- Wenn die Argumentdeduktion fehlschlägt oder die synthetisierte Funktions-Template-Spezialisierung fehlerhaft wäre, wird keine solche Funktion zur Kandidatenmenge hinzugefügt (siehe SFINAE ).
Wenn ein Name auf eine oder mehrere Funktionsschablonen verweist und auch auf eine Menge überladener Nicht-Schablonenfunktionen, sind diese Funktionen und die aus den Schablonen generierten Spezialisierungen alle Kandidaten.
Siehe function template overloading für weitere Details.
|
Wenn ein Konstruktor-Template oder eine Konvertierungsfunktions-Template einen bedingten explicit-Spezifizierer besitzt, der wertabhängig ist, wird nach der Deduktion, falls der Kontext einen Kandidaten erfordert, der nicht explicit ist und die generierte Spezialisierung explicit ist, diese aus dem Kandidatensatz entfernt. |
(seit C++20) |
Zusätzliche Regeln für Konstruktorkandidaten
|
Standardmäßig generierte Move-Konstruktoren und Move-Zuweisungsoperatoren , die als gelöscht definiert sind, werden aus der Menge der Kandidatenfunktionen ausgeschlossen.
Ein von einem Klassentyp
|
(seit C++11) |
Zusätzliche Regeln für Member-Funktions-Kandidaten
Wenn eine Kandidatenfunktion eine Memberfunktion (statisch oder nicht-statisch) ist, die keinen expliziten Objektparameter besitzt (seit C++23) , aber kein Konstruktor, wird sie so behandelt, als hätte sie einen zusätzlichen Parameter ( impliziter Objektparameter ), der das Objekt repräsentiert, für das sie aufgerufen wird, und der vor dem ersten der tatsächlichen Parameter erscheint.
Ebenso wird das Objekt, auf dem eine Memberfunktion aufgerufen wird, der Argumentenliste als das implied object argument vorangestellt.
Für Elementfunktionen der Klasse
X
wird der Typ des impliziten Objektparameters durch CV-Qualifizierungen und Ref-Qualifizierungen der Elementfunktion beeinflusst, wie in
member functions
beschrieben.
Die benutzerdefinierten Konvertierungsfunktionen werden als Mitglieder des implied object argument betrachtet, um den Typ des implicit object parameter zu bestimmen.
Die durch eine using-Deklaration in eine abgeleitete Klasse eingeführten Memberfunktionen werden für die Definition des Typs des impliziten Objektparameters als Member der abgeleiteten Klasse betrachtet .
|
Für statische Memberfunktionen wird der implizite Objektparameter als mit jedem Objekt übereinstimmend betrachtet: Sein Typ wird nicht untersucht und keine Konvertierungssequenz wird für ihn versucht. |
(bis C++23) |
Für den Rest der Überladungsauflösung ist das implied object argument von anderen Argumenten nicht zu unterscheiden, aber die folgenden speziellen Regeln gelten für den implicit object parameter :
struct B { void f(int); }; struct A { operator B&(); }; A a; a.B::f(1); // Fehler: benutzerdefinierte Konvertierungen können nicht // auf den impliziten Objektparameter angewendet werden static_cast<B&>(a).f(1); // OK
Viable functions
Angesichts der Menge der Kandidatenfunktionen, die wie oben beschrieben konstruiert wurde, besteht der nächste Schritt der Überlagerungsauflösung darin, Argumente und Parameter zu untersuchen, um die Menge auf die Menge der viable functions zu reduzieren
Um in die Menge der geeigneten Funktionen aufgenommen zu werden, muss die Kandidatenfunktion Folgendes erfüllen:
M
Argumente gibt, ist die Kandidatenfunktion, die genau
M
Parameter hat, geeignet
M
Parameter hat, aber einen
Ellipsenparameter
besitzt, ist sie verwendbar.
M
Parameter hat und der
M+1
-te Parameter und alle folgenden Parameter Standardargumente haben, ist sie geeignet. Für den Rest der Überladungsauflösung wird die Parameterliste bei
M
abgeschnitten.
|
4)
Wenn die Funktion eine assoziierte
Constraint
besitzt, muss diese erfüllt sein
|
(since C++20) |
Benutzerdefinierte Konvertierungen (sowohl konvertierende Konstruktoren als auch benutzerdefinierte Konvertierungsfunktionen) sind von der Teilnahme an impliziten Konvertierungssequenzen ausgeschlossen, wenn dies die Anwendung mehr als einer benutzerdefinierten Konvertierung ermöglichen würde. Insbesondere werden sie nicht berücksichtigt, wenn das Ziel der Konvertierung der erste Parameter eines Konstruktors oder der implizite Objektparameter einer benutzerdefinierten Konvertierungsfunktion ist und dieser Konstruktor/diese benutzerdefinierte Konvertierung ein Kandidat für
- Copy-Initialisierung einer Klasse durch benutzerdefinierte Konvertierung ,
- Initialisierung eines Nicht-Klassen-Typs durch eine Konvertierungsfunktion ,
- Initialisierung durch Konvertierungsfunktion für direkte Referenzbindung ,
- Initialisierung durch Konstruktor während des zweiten (Direct-Initialization) Schritts der Copy-Initialisierung einer Klasse,
struct A { A(int); }; struct B { B(A); }; B b{{0}}; // Listeninitialisierung von B // Kandidaten: B(const B&), B(B&&), B(A) // {0} -> B&& nicht anwendbar: müsste B(A) aufrufen // {0} -> const B&: nicht anwendbar: müsste an Rvalue binden, müsste B(A) aufrufen // {0} -> A anwendbar. Ruft A(int) auf: benutzerdefinierte Konvertierung nach A ist nicht verboten |
(seit C++11) |
Beste geeignete Funktion
Für jedes Paar von geeigneten Funktionen
F1
und
F2
werden die impliziten Konvertierungssequenzen vom
i
ten
Argument zum
i
ten
Parameter rangiert, um zu bestimmen, welche besser ist (außer beim ersten Argument - das
implizite Objektargument
für statische Memberfunktionen hat keine Auswirkung auf die Rangfolge)
F1
wird als eine bessere Funktion als
F2
bestimmt, wenn implizite Konvertierungen für alle Argumente von
F1
nicht schlechter
sind als die impliziten Konvertierungen für alle Argumente von F2, und
F1
, dessen implizite Konvertierung
besser
ist als die entsprechende implizite Konvertierung für dieses Argument von
F2
, oder, falls nicht zutreffend,
F1
zum zu initialisierenden Typ ist
besser
als die Standardkonvertierungssequenz vom Ergebnis von
F2
, oder, falls nicht,
|
3)
(nur im Kontext der Initialisierung durch Konvertierungsfunktion für direkte Referenzbindung einer Referenz auf Funktionstyp), ist das Ergebnis von
F1
die gleiche Art von Referenz (Lvalue oder Rvalue) wie die zu initialisierende Referenz, und das Ergebnis von
F2
ist es nicht, oder, falls nicht zutreffend,
|
(since C++11) |
F1
ist eine Nicht-Template-Funktion, während
F2
eine Template-Spezialisierung ist, oder, falls nicht,
F1
und
F2
sind beide Template-Spezialisierungen und
F1
ist gemäß den
Partiellen Ordnungsregeln für Template-Spezialisierungen
spezialisierter, oder, falls nicht zutreffend,
|
6)
F1
und
F2
sind Nicht-Template-Funktionen und
F1
ist
stärker partial-ordering-constrained
als
F2
:
template<typename T = int> struct S { constexpr void f(); // #1 constexpr void f(this S&) requires true; // #2 }; void test() { S<> s; s.f(); // calls #2 }
, oder, falls nicht zutreffend,
|
(seit C++20) |
|
7)
F1
ist ein Konstruktor für eine Klasse
D
,
F2
ist ein Konstruktor für eine Basisklasse
B
von
D
, und für alle Argumente haben die entsprechenden Parameter von
F1
und
F2
denselben Typ:
struct A { A(int = 0); }; struct B: A { using A::A; B(); }; B b; // OK, B::B()
, oder, falls nicht,
|
(seit C++11) |
|
8)
F2
ist ein umgeschriebener Kandidat und
F1
ist es nicht, oder, falls nicht zutreffend,
9)
F1
und
F2
sind beide umgeschriebene Kandidaten, und
F2
ist ein synthetisierter umgeschriebener Kandidat mit umgekehrter Parameterreihenfolge und
F1
ist es nicht, oder, falls nicht zutreffend,
|
(since C++20) |
|
10)
F1
wird aus einem
benutzerdefinierten Deduktionsleitfaden
generiert und
F2
nicht, oder falls nicht zutreffend,
12)
F1
wird aus einem Nicht-Template-Konstruktor generiert und
F2
wird aus einem Konstruktortemplate generiert:
template<class T> struct A { using value_type = T; A(value_type); // #1 A(const A&); // #2 A(T, T, int); // #3 template<class U> A(int, T, U); // #4 }; // #5 ist A(A), der Kopierdeduktionskandidat A x(1, 2, 3); // verwendet #3, generiert aus einem Nicht-Template-Konstruktor template<class T> A(T) -> A<T>; // #6, weniger spezialisiert als #5 A a (42); // verwendet #6 zur Deduktion von A<int> und #1 zur Initialisierung A b = a; // verwendet #5 zur Deduktion von A<int> und #2 zur Initialisierung template<class T> A(A<T>) -> A<A<T>>; // #7, ebenso spezialisiert wie #5 A b2 = a; // verwendet #7 zur Deduktion von A<A<int>> und #1 zur Initialisierung |
(seit C++17) |
Diese paarweisen Vergleiche werden auf alle geeigneten Funktionen angewendet. Wenn genau eine geeignete Funktion besser als alle anderen ist, gelingt die Überladungsauflösung und diese Funktion wird aufgerufen. Andernfalls schlägt die Kompilierung fehl.
void Fcn(const int*, short); // Überladung #1 void Fcn(int*, int); // Überladung #2 int i; short s = 0; void f() { Fcn(&i, 1L); // 1. Argument: &i -> int* ist besser als &i -> const int* // 2. Argument: 1L -> short und 1L -> int sind äquivalent // ruft Fcn(int*, int) auf Fcn(&i, 'c'); // 1. Argument: &i -> int* ist besser als &i -> const int* // 2. Argument: 'c' -> int ist besser als 'c' -> short // ruft Fcn(int*, int) auf Fcn(&i, s); // 1. Argument: &i -> int* ist besser als &i -> const int* // 2. Argument: s -> short ist besser als s -> int // kein Gewinner, Kompilierungsfehler }
Wenn die beste geeignete Funktion zu einer Funktion aufgelöst wird, für die mehrere Deklarationen gefunden wurden, und wenn irgendwelche zwei dieser Deklarationen sich in unterschiedlichen Gültigkeitsbereichen befinden und ein Standardargument angeben, das die Funktion geeignet gemacht hat, ist das Programm fehlerhaft.
namespace A { extern "C" void f(int = 5); } namespace B { extern "C" void f(int = 5); } using A::f; using B::f; void use() { f(3); // OK, Standardargument wurde nicht für die Tauglichkeit verwendet f(); // Fehler: Standardargument zweimal gefunden }
Rangfolge impliziter Konvertierungssequenzen
Die von der Überladungsauflösung betrachteten Argument-Parameter implizite Konvertierungssequenzen entsprechen den impliziten Konvertierungen , die bei der Kopierinitialisierung verwendet werden (für Nicht-Referenzparameter), mit der Ausnahme, dass bei der Betrachtung der Konvertierung zum impliziten Objektparameter oder zur linken Seite des Zuweisungsoperators Konvertierungen, die temporäre Objekte erzeugen, nicht berücksichtigt werden. Wenn der Parameter der implizite Objektparameter einer statischen Memberfunktion ist, ist die implizite Konvertierungssequenz eine Standardkonvertierungssequenz, die weder besser noch schlechter als jede andere Standardkonvertierungssequenz ist. (seit C++23)
Jeder Typ von Standardkonvertierungssequenz wird einem von drei Rängen zugeordnet:
Der Rang der Standardkonvertierungssequenz ist der schlechteste der Ränge der Standardkonversionen, die sie enthält (es können bis zu drei Konversionen vorkommen)
Die Bindung eines Referenzparameters direkt an den Argumentausdruck ist entweder Identität oder eine Derived-to-Base-Konvertierung:
struct Base {}; struct Derived : Base {} d; int f(Base&); // Überladung #1 int f(Derived&); // Überladung #2 int i = f(d); // d -> Derived& hat Rang Exakte Übereinstimmung // d -> Base& hat Rang Konvertierung // ruft f(Derived&) auf
Da die Rangfolge von Konvertierungssequenzen nur mit Typen und Wertkategorien arbeitet, kann ein Bitfeld für die Zwecke der Rangfolge an ein Referenzargument binden, aber wenn diese Funktion ausgewählt wird, wird sie fehlerhaft sein.
S1
ist
besser
als eine Standardkonvertierungssequenz
S2
wenn
S1
ist eine echte Teilsequenz von
S2
, unter Ausschluss von Lvalue-Transformationen; die Identitätskonvertierungssequenz wird als Teilsequenz jeder nicht-identischen Konvertierung betrachtet, oder, falls nicht zutreffend,
S1
ist besser als der Rang von
S2
, oder, falls nicht,
S1
als auch
S2
binden an einen Referenzparameter für etwas anderes als den impliziten Objektparameter einer ref-qualifizierten Memberfunktion, und
S1
bindet eine Rvalue-Referenz an einen Rvalue, während
S2
eine Lvalue-Referenz an einen Rvalue bindet:
int i; int f1(); int g(const int&); // Überladung #1 int g(const int&&); // Überladung #2 int j = g(i); // Lvalue int -> const int& ist die einzige gültige Konvertierung int k = g(f1()); // Rvalue int -> const int&& besser als Rvalue int -> const int&
S1
und
S2
binden an einen Referenzparameter und
S1
bindet eine Lvalue-Referenz auf Funktion, während
S2
eine Rvalue-Referenz auf Funktion bindet:
int f(void(&)()); // Überladung #1 int f(void(&&)()); // Überladung #2 void g(); int i1 = f(g); // ruft #1 auf
S1
und
S2
unterscheiden sich nur in der Qualifikationskonvertierung, und
|
die CV-Qualifikation des Ergebnisses von
|
(bis C++20) |
|
das Ergebnis von
|
(seit C++20) |
int f(const int*); int f(int*); int i; int j = f(&i); // &i -> int* is better than &i -> const int*, calls f(int*)
S1
und
S2
binden an Referenzparameter, die sich nur in der obersten cv-Qualifikation unterscheiden, und
S1
's Typ ist
weniger
cv-qualifiziert als
S2
's:
int f(const int &); // Überladung #1 int f(int &); // Überladung #2 (beide Referenzen) int g(const int &); // Überladung #1 int g(int); // Überladung #2 int i; int j = f(i); // Lvalue i -> int& ist besser als Lvalue int -> const int& // ruft f(int&) auf int k = g(i); // Lvalue i -> const int& bewertet als Exakte Übereinstimmung // Lvalue i -> Rvalue int bewertet als Exakte Übereinstimmung // mehrdeutige Überladung: Kompilierungsfehler
S1
und
S2
binden denselben Referenztyp "Referenz auf
T
" und haben Quelltypen
V1
bzw.
V2
, wobei die Standardkonvertierungssequenz von
V1
*
zu
T
*
besser ist als die Standardkonvertierungssequenz von
V2
*
zu
T
*
:
struct Z {}; struct A { operator Z&(); operator const Z&(); // Überladung #1 }; struct B { operator Z(); operator const Z&&(); // Überladung #2 }; const Z& r1 = A(); // OK, verwendet #1 const Z&& r2 = B(); // OK, verwendet #2
U1
ist
besser
als eine benutzerdefinierte Konvertierungssequenz
U2
, wenn sie denselben Konstruktor/dieselbe benutzerdefinierte Konvertierungsfunktion aufrufen oder dieselbe Klasse mit Aggregatinitialisierung initialisieren, und in beiden Fällen die zweite Standardkonvertierungssequenz in
U1
besser ist als die zweite Standardkonvertierungssequenz in
U2
struct A { operator short(); // user-defined conversion function } a; int f(int); // overload #1 int f(float); // overload #2 int i = f(a); // A -> short, followed by short -> int (rank Promotion) // A -> short, followed by short -> float (rank Conversion) // calls f(int)
L1
ist
besser
als Listeninitialisierungssequenz
L2
, wenn
L1
einen
std::initializer_list
-Parameter initialisiert, während
L2
dies nicht tut.
void f1(int); // #1 void f1(std::initializer_list<long>); // #2 void g1() { f1({42}); } // chooses #2 void f2(std::pair<const char*, const char*>); // #3 void f2(std::initializer_list<std::string>); // #4 void g2() { f2({"foo", "bar"}); } // chooses #4
|
6)
Eine Listeninitialisierungssequenz
L1
ist
besser
als Listeninitialisierungssequenz
L2
, wenn die entsprechenden Parameter Referenzen auf Arrays sind, und L1 zu Typ "Array von N1 T" konvertiert, L2 zu "Array von N2 T" konvertiert, und N1 kleiner als N2 ist.
|
(since C++11)
(until C++20) |
|
6)
Eine Listeninitialisierungssequenz
L1
ist
besser
als Listeninitialisierungssequenz
L2
, wenn die entsprechenden Parameter Referenzen auf Arrays sind, und L1 und L2 zu Arrays desselben Elementtyps konvertieren, und entweder
void f(int (&&)[] ); // overload #1 void f(double (&&)[] ); // overload #2 void f(int (&&)[2]); // overload #3 f({1}); // #1: Better than #2 due to conversion, better than #3 due to bounds f({1.0}); // #2: double -> double is better than double -> int f({1.0, 2.0}); // #2: double -> double is better than double -> int f({1, 2}); // #3: -> int[2] is better than -> int[], // and int -> int is better than int -> double |
(since C++20) |
Wenn zwei Konvertierungssequenzen nicht unterscheidbar sind, weil sie denselben Rang haben, gelten die folgenden zusätzlichen Regeln:
|
2)
Eine Konvertierung, die eine
Enumeration
mit festgelegtem zugrundeliegenden Typ zu ihrem zugrundeliegenden Typ heraufstuft, ist besser als eine, die zum heraufgestuften zugrundeliegenden Typ konvertiert, falls die beiden Typen unterschiedlich sind.
enum num : char { one = '0' }; std::cout << num::one; // '0', not 48 |
(since C++11) |
|
3)
Eine Konvertierung in beide Richtungen zwischen Gleitkommatyp
FP1
und Gleitkommatyp
FP2
ist besser als eine Konvertierung in dieselbe Richtung zwischen
FP1
und arithmetischem Typ
T3
, wenn
int f(std::float32_t); int f(std::float64_t); int f(long long); float x; std::float16_t y; int i = f(x); // calls f(std::float32_t) on implementations where // float and std::float32_t have equal conversion ranks int j = f(y); // error: ambiguous, no equal conversion rank |
(seit C++23) |
Mid
(direkt oder indirekt) von
Base
abgeleitet ist, und
Derived
(direkt oder indirekt) von
Mid
abgeleitet ist
Derived
nach
Mid
&
oder
Mid
&&
ist besser als
Derived
nach
Base
&
oder
Base
&&
Derived
zu
Mid
ist besser als
Derived
zu
Base
Mid
nach
Base
&
oder
Base
&&
ist besser als
Derived
nach
Base
&
oder
Base
&&
Mid
zu
Base
ist besser als
Derived
zu
Base
Mehrdeutige Konvertierungssequenzen werden als benutzerdefinierte Konvertierungssequenzen eingestuft, da mehrere Konvertierungssequenzen für ein Argument nur dann existieren können, wenn sie unterschiedliche benutzerdefinierte Konvertierungen betreffen:
class B; class A { A (B&);}; // Konvertierungskonstruktor class B { operator A (); }; // benutzerdefinierte Konvertierungsfunktion class C { C (B&); }; // Konvertierungskonstruktor void f(A) {} // Überladung #1 void f(C) {} // Überladung #2 B b; f(b); // B -> A via Konstruktor oder B -> A via Funktion (mehrdeutige Konvertierung) // b -> C via Konstruktor (benutzerdefinierte Konvertierung) // die Konvertierungen für Überladung #1 und für Überladung #2 // sind nicht unterscheidbar; Kompilierung schlägt fehl
Implizite Konvertierungssequenz bei Listeninitialisierung
Bei der Listeninitialisierung ist das Argument ein braced-init-list , was kein Ausdruck ist, daher wird die implizite Konvertierungssequenz in den Parametertyp für die Überladungsauflösung durch die folgenden speziellen Regeln bestimmt:
-
Wenn der Parametertyp ein Aggregat
Xist und die Initialisierungsliste genau ein Element desselben oder eines abgeleiteten Typs (möglicherweise cv-qualifiziert) enthält, ist die implizite Konvertierungssequenz diejenige, die erforderlich ist, um das Element in den Parametertyp zu konvertieren. - Andernfalls, wenn der Parametertyp eine Referenz auf ein Zeichenarray ist und die Initialisierungsliste ein einzelnes Element enthält, das ein Zeichenkettenliteral mit passendem Typ ist, ist die implizite Konvertierungssequenz die Identitätskonvertierung.
-
Andernfalls, wenn der Parametertyp
std::
initializer_list
<
X
>
ist und es für jedes Element der Initialisierungsliste eine nicht-einschränkende implizite Konvertierung zu
Xgibt, ist die implizite Konvertierungssequenz für die Überladungsauflösung die schlechteste notwendige Konvertierung. Wenn die geschweifte Initialisierungsliste leer ist, ist die Konvertierungssequenz die Identitätskonvertierung.
struct A { A(std::initializer_list<double>); // #1 A(std::initializer_list<complex<double>>); // #2 A(std::initializer_list<std::string>); // #3 }; A a{1.0, 2.0}; // wählt #1 aus (rvalue double -> double: Identitätskonvertierung) void g(A); g({"foo", "bar"}); // wählt #3 aus (lvalue const char[4] -> std::string: benutzerdefinierte Konvertierung)
-
Andernfalls, wenn der Parametertyp "Array von N T" ist (dies tritt nur bei Referenzen auf Arrays auf), muss die Initialisierungsliste N oder weniger Elemente haben, und die schlechteste implizite Konvertierung, die notwendig ist, um jedes Element der Liste (oder das leere Paar geschweifter Klammern
{}wenn die Liste kürzer als N ist) zuTzu konvertieren, wird verwendet.
|
(since C++20) |
typedef int IA[3]; void h(const IA&); void g(int (&&)[]); h({1, 2, 3}); // int->int Identitätskonvertierung g({1, 2, 3}); // dasselbe wie oben seit C++20
-
Andernfalls, wenn der Parametertyp ein nicht-aggregierter Klassentyp
Xist, wählt die Überladungsauflösung den Konstruktor C von X zur Initialisierung aus der Argument-Initialisierungsliste
-
- Wenn C kein Initialisierer-Listen-Konstruktor ist und die Initialisiererliste ein einzelnes Element vom möglicherweise cv-qualifizierten Typ X enthält, hat die implizite Konvertierungssequenz den Rang Exact Match. Wenn die Initialisiererliste ein einzelnes Element vom möglicherweise cv-qualifizierten Typ abgeleitet von X enthält, hat die implizite Konvertierungssequenz den Rang Conversion. (beachte den Unterschied zu Aggregaten: Aggregate initialisieren direkt aus Einzelelement-Initialisiererlisten vor der Berücksichtigung von aggregate initialization , Nicht-Aggregate berücksichtigen initializer_list-Konstruktoren vor allen anderen Konstruktoren)
- andernfalls ist die implizite Konvertierungssequenz eine benutzerdefinierte Konvertierungssequenz mit der zweiten Standardkonvertierungssequenz als Identitätskonvertierung.
Wenn mehrere Konstruktoren geeignet sind, aber keiner besser als die anderen ist, ist die implizite Konvertierungssequenz die mehrdeutige Konvertierungssequenz.
struct A { A(std::initializer_list<int>); }; void f(A); struct B { B(int, double); }; void g(B); g({'a', 'b'}); // ruft g(B(int, double)) auf, benutzerdefinierte Konvertierung // g({1.0, 1,0}); // Fehler: double->int ist eine Verengung, in Listeninitialisierung nicht erlaubt void f(B); // f({'a', 'b'}); // f(A) und f(B) beide benutzerdefinierte Konvertierungen
- Andernfalls, wenn der Parametertyp ein Aggregat ist, das aus der Initialisierungsliste gemäß Aggregatinitialisierung initialisiert werden kann, ist die implizite Konvertierungssequenz eine benutzerdefinierte Konvertierungssequenz mit der zweiten Standardkonvertierungssequenz als Identitätskonvertierung.
struct A { int m1; double m2; }; void f(A); f({'a', 'b'}); // ruft f(A(int, double)) auf, benutzerdefinierte Konvertierung
- Andernfalls, wenn der Parameter eine Referenz ist, gelten die Regeln für die Referenzinitialisierung
struct A { int m1; double m2; }; void f(const A&); f({'a', 'b'}); // Temporäres Objekt erstellt, f(A(int, double)) aufgerufen. Benutzerdefinierte Konvertierung
- Andernfalls, wenn der Parametertyp keine Klasse ist und die Initialisierungsliste ein Element hat, ist die implizite Konvertierungssequenz diejenige, die erforderlich ist, um das Element in den Parametertyp zu konvertieren.
- Andernfalls, wenn der Parametertyp kein Klassentyp ist und die Initialisierungsliste keine Elemente hat, ist die implizite Konvertierungssequenz die Identitätskonvertierung.
|
Wenn das Argument eine Designated Initializer List ist und der Parameter keine Referenz ist, ist eine Konvertierung nur möglich, wenn der Parameter einen Aggregattyp hat, der gemäß den Regeln für Aggregatinitialisierung von dieser Initialisiererliste initialisiert werden kann. In diesem Fall ist die implizite Konvertierungssequenz eine benutzerdefinierte Konvertierungssequenz, deren zweite Standardkonvertierungssequenz eine Identitätskonvertierung ist. Wenn nach dem Overload Resolution die Deklarationsreihenfolge der Aggregate-Member nicht mit der ausgewählten Überladung übereinstimmt, ist die Initialisierung des Parameters fehlerhaft. struct A { int x, y; }; struct B { int y, x; }; void f(A a, int); // #1 void f(B b, ...); // #2 void g(A a); // #3 void g(B b); // #4 void h() { f({.x = 1, .y = 2}, 0); // OK; calls #1 f({.y = 2, .x = 1}, 0); // error: selects #1, initialization of a fails // due to non-matching member order g({.x = 1, .y = 2}); // error: ambiguous between #3 and #4 }
|
(seit C++20) |
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Veröffentlichtes Verhalten | Korrektes Verhalten |
|---|---|---|---|
| CWG 1 | C++98 |
das Verhalten war nicht spezifiziert, wenn dieselbe
Funktion mit möglicherweise unterschiedlichen Standard- argumenten (aus verschiedenen Gültigkeitsbereichen) ausgewählt wird |
das Programm ist in diesem Fall fehler-
haft |
| CWG 83 | C++98 |
die Konvertierungssequenz von einem String-Literal
zu char * war besser als die zu const char * obwohl erstere als veraltet galt |
der Rang der veralteten
Konvertierung wurde herabgestuft (sie wurde in C++11 entfernt) |
| CWG 162 | C++98 |
es war ungültig, wenn die durch
F
benannte Überladungsmenge
eine nicht-statische Memberfunktion im Fall von
&F(args)
enthält
|
nur ungültig, wenn Überladungsauflösung
in diesem Fall eine nicht-statische Memberfunktion auswählt |
| CWG 233 | C++98 |
Referenzen und Zeiger wurden inkonsistent behandelt in
Überladungsauflösung mit benutzerdefinierten Konvertierungen |
sie werden
konsistent behandelt |
| CWG 280 | C++98 |
Ersatzaufruffunktionen wurden nicht zum
Satz der Kandidatenfunktionen für Konvertierungs- funktionen hinzugefügt, die in unzugänglichen Basisklassen deklariert sind |
entfernte die Zugänglichkeits-
beschränkung, das Programm ist fehlerhaft, wenn eine Ersatzaufruffunktion ausgewählt wird und die entsprechende Konvertierungs- funktion nicht aufgerufen werden kann |
| CWG 415 | C++98 |
wenn eine Funktionsvorlage als Kandidat
ausgewählt wurde, wurden ihre Spezialisierungen mittels Template-Argument-Deduktion instanziiert |
in diesem Fall erfolgt keine Instanziierung,
ihre Deklarationen werden synthetisiert |
| CWG 495 | C++98 |
Wenn die impliziten Konvertierungen für Argumente gleichwertig
sind, war eine Nicht-Template-Konvertierungsfunktion stets besser als eine Konvertierungsfunktionsvorlage, selbst wenn letztere eine bessere Standardkonvertierungssequenz haben könnte |
Standardkonvertierungs-
sequenzen werden vor Spezialisierungsgraden verglichen |
| CWG 1307 | C++11 | Überladungsauflösung basierend auf der Größe von Arrays war nicht spezifiziert |
ein kürzeres Array ist
besser wenn möglich |
| CWG 1328 | C++11 |
Die Bestimmung der Kandidatenfunktionen beim
Binden einer Referenz an ein Konvertierungsergebnis war nicht klar |
klargestellt |
| CWG 1374 | C++98 |
Qualifikationskonvertierung wurde vor Referenzbindung geprüft
beim Vergleich von Standardkonvertierungssequenzen |
umgekehrt |
| CWG 1385 | C++11 |
Eine nicht-explizite benutzerdefinierte Konvertierungsfunktion, die mit
einem Ref-Qualifier deklariert wurde, hatte keine entsprechende Ersatzfunktion |
Sie hat eine entsprechende
Ersatzfunktion |
| CWG 1467 | C++11 |
Gleichartige Listeninitialisierung von
Aggregaten und Arrays wurde ausgelassen |
Initialisierung definiert |
| CWG 1601 | C++11 |
Konvertierung von Enum in seinen zugrundeliegenden Typ
bevorzugte nicht den festgelegten zugrundeliegenden Typ |
fester Typ wird bevorzugt
gegenüber dem, worin er promoviert |
| CWG 1608 | C++98 |
Die Menge der Mitgliederkandidaten eines unären Operators
@
dessen Argument den Typ
T1
hat, war leer, wenn
T1
eine Klasse ist, die gerade definiert wird
|
Die Menge ist das Ergebnis
der qualifizierten Namenssuche von
T1::operator@
in diesem Fall
|
| CWG 1687 | C++98 |
wenn ein eingebauter Kandidat durch Überladungsauflösung ausgewählt wird,
würden die Operanden ohne Einschränkung konvertiert werden |
nur Klassentyp-Operanden konvertieren,
und die zweite Standardkonvertierungssequenz deaktiviert |
| CWG 2052 | C++98 |
fehlerhaft synthetisierte Funktions-Templatespezialisierungen konnten
zum Kandidatensatz hinzugefügt werden, wodurch das Programm fehlerhaft wurde |
sie werden nicht zum
Kandidatensatz hinzugefügt |
| CWG 2076 | C++11 |
Benutzerdefinierte Konvertierung wird auf den einzelnen Initialisierer
in einer geschachtelten Initialisiererliste während der Listeninitialisierung angewendet aufgrund der Lösung von CWG Issue 1467 |
nicht angewendet |
| CWG 2137 | C++11 |
Initialisierungslisten-Konstruktoren gehen verloren gegenüber Kopier-
konstruktoren bei der Listeninitialisierung von
X
aus
{
X
}
|
Nicht-Aggregate berücksichtigen
Initialisierungslisten zuerst |
| CWG 2273 | C++11 |
es gab keinen Tiebreaker zwischen
geerbten und nicht geerbten Konstruktoren |
nicht geerbter Konstruktor gewinnt |
| CWG 2673 | C++20 |
Eingebaute Kandidaten mit derselben Parameterliste
wie ein umgeschriebener Nicht-Mitglied-Kandidat wurden zur Liste der eingebauten Kandidaten hinzugefügt |
nicht hinzugefügt |
| CWG 2712 | C++98 |
wenn ein eingebauter Zuweisungsoperator betrachtet wird,
konnte der erste Parameter nicht an ein temporäres Objekt gebunden werden, was bereits unmöglich ist [1] |
entfernte die
redundante Anforderung |
| CWG 2713 | C++20 |
die Umwandlungseinschränkung bezüglich Designated-Initializer-Listen
wurde auch angewendet, wenn der Parameter eine Referenz ist |
in diesem Fall nicht eingeschränkt |
| CWG 2789 | C++23 |
der explizite Objektparameter wurde berücksichtigt
beim Vergleichen von Parameter-Typ-Listen |
ausgeschlossen |
| CWG 2856 | C++11 |
die Überladungsauflösung für Standardinitialisierung im Kontext
der Kopier-Listeninitialisierung berücksichtigte nur konvertierende Konstruktoren |
berücksichtigt alle Konstruktoren |
| CWG 2919 | C++98 |
der Kandidatensatz der Referenzinitialisierung durch Konvertierung
hing vom Zieltyp der Initialisierung ab |
hängt vom Zieltyp
der Konvertierung ab |
| P2468R2 | C++20 |
Umgeschriebene Kandidaten basierend auf
operator
==
werden hinzugefügt
für a ! = b selbst wenn ein passender operator ! = existiert |
nicht hinzugefügt |
-
↑
Der Typ des ersten Parameters eines eingebauten Zuweisungsoperators ist "Lvalue-Referenz auf möglicherweise volatile-qualifiziertes
T". Referenzen dieses Typs können nicht an ein temporäres Objekt gebunden werden.
Referenzen
- C++23-Standard (ISO/IEC 14882:2024):
-
- 12.2 Overload resolution [over.match]
- C++20-Standard (ISO/IEC 14882:2020):
-
- 12.4 Overload-Auflösung [over.match]
- C++17-Standard (ISO/IEC 14882:2017):
-
- 16.3 Überladungsauflösung [over.match]
- C++14-Standard (ISO/IEC 14882:2014):
-
- 13.3 Überladungsauflösung [over.match]
- C++11 Standard (ISO/IEC 14882:2011):
-
- 13.3 Überladungsauflösung [over.match]
- C++03 Standard (ISO/IEC 14882:2003):
-
- 13.3 Overload resolution [over.match]