Überladungsauflösung
Um einen Funktionsaufruf zu kompilieren, muss der Compiler zunächst eine Namenssuche durchführen, die für Funktionen eine Argument-abhängige Suche beinhalten kann, und für Funktion-Templates kann dies von einer Template-Argument-Ableitung gefolgt werden.
Wenn der Name auf mehr als eine Entität verweist, ist er überladen, und der Compiler muss entscheiden, welche Überladung aufgerufen werden soll. Vereinfacht ausgedrückt wird die Überladung aufgerufen, deren Parameter am besten zu den Argumenten passen.
Im Detail erfolgt die Überladungsauflösung durch die folgenden Schritte:
- Erstellung der Menge der Kandidatenfunktionen.
- Einschränkung der Menge auf nur gültige Funktionen.
- Analyse der Menge zur Bestimmung der einzelnen besten gültigen Funktion (dies kann die Rangfolge impliziter Konversionssequenzen beinhalten).
void f(long); void f(float); f(0L); // calls f(long) f(0); // error: ambiguous overload
Neben Funktionsaufrufen können überladene Funktionsnamen in mehreren zusätzlichen Kontexten auftreten, wo andere Regeln gelten: siehe Adresse einer überladenen Funktion.
Wenn eine Funktion nicht durch Überladungsauflösung ausgewählt werden kann, kann sie nicht verwendet werden (z.B. ist sie eine Template-Entität mit einer fehlgeschlagenen Beschränkung).
[edit] Kandidatenfunktionen
Bevor die Überladungsauflösung beginnt, werden die durch Namenssuche und Template-Argument-Ableitung ausgewählten Funktionen zu der Menge der Kandidatenfunktionen kombiniert. Die genauen Details hängen vom Kontext ab, in dem die Überladungsauflösung stattfindet.
[edit] Aufruf einer benannten Funktion
Wenn E in einem Funktionsaufrufausdruck E(args) einen Satz überladener Funktionen und/oder Funktion-Templates bezeichnet (aber keine aufrufbaren Objekte), gelten die folgenden Regeln:
- Wenn der Ausdruck E die Form PA->B oder A.B hat (wobei A vom Klassentyp cv
Tist), dann wird B als Memberfunktion vonTgesucht. Die durch diese Suche gefundenen Funktionsdeklarationen sind die Kandidatenfunktionen. Die Argumentliste für den Zweck der Überladungsauflösung enthält das implizite Objektargument vom Typ cvT. - Wenn der Ausdruck E ein primärer Ausdruck ist, wird der Name gemäß den normalen Regeln für Funktionsaufrufe gesucht (was ADL beinhalten kann). Die durch diese Suche gefundenen Funktionsdeklarationen sind (aufgrund der Funktionsweise der Suche) entweder
- nur Nicht-Member-Funktionen (in diesem Fall ist die Argumentliste für den Zweck der Überladungsauflösung genau die Argumentliste, die im Funktionsaufruf-Ausdruck verwendet wird)
- nur Member-Funktionen einer Klasse
T. In diesem Fall, wenn this im Gültigkeitsbereich liegt und ein Zeiger aufToder eine abgeleitete Klasse vonTist, wird *this als implizites Objektargument verwendet. Andernfalls (wenn this nicht im Gültigkeitsbereich liegt oder nicht aufTzeigt), wird ein Dummy-Objekt vom TypTals implizites Objektargument verwendet, und wenn die Überladungsauflösung anschließend eine nicht-statische Memberfunktion auswählt, ist das Programm ill-formed.
[edit] Aufruf eines Klassenobjekts
Wenn E in einem Funktionsaufrufausdruck E(args) vom Klassentyp cv T ist, dann:
- Die Funktionsaufrufoperatoren von
Twerden durch eine normale Suche 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 Konversionsfunktion inToder einer Basis vonT(sofern nicht versteckt), deren cv-Qualifizierer die gleichen oder höhere sind als die vonT, und wo die Konversionsfunktion zu
- einem Zeiger auf eine Funktion
- einer Referenz auf einen Zeiger auf eine Funktion
- einer Referenz auf eine Funktion
- konvertiert, wird eine Surrogat-Aufruffunktion mit einem eindeutigen Namen erstellt, deren erster Parameter das Ergebnis der Konversion ist, die verbleibenden Parameter die vom Ergebnis der Konversion akzeptierte Parameterliste sind und deren Rückgabetyp der Rückgabetyp des Ergebnisses der Konversion ist. Diese Surrogat-Aufruffunktion wird zur Menge der Kandidatenfunktionen hinzugefügt. Wenn diese Surrogatfunktion durch die anschließende Überladungsauflösung ausgewählt wird, wird die benutzerdefinierte Konversionsfunktion aufgerufen und dann das Ergebnis der Konversion aufgerufen.
In jedem Fall besteht die Argumentliste für den Zweck der Überladungsauflösung aus der Argumentliste des Funktionsaufruf-Ausdrucks, dem das implizite Objektargument E vorangestellt ist (beim Abgleich mit der Surrogatfunktion konvertiert die benutzerdefinierte Konversion automatisch das implizite Objektargument in das erste Argument der Surrogatfunktion).
int f1(int); int f2(float); struct A { using fp1 = int(*)(int); operator fp1() { return f1; } // conversion function to pointer to function using fp2 = int(*)(float); operator fp2() { return f2; } // conversion function to pointer to function } a; int i = a(1); // calls f1 via pointer returned from conversion function
[edit] Aufruf eines überladenen Operators
Wenn mindestens eines der Argumente eines Operators in einem Ausdruck einen Klassentyp oder einen Aufzählungstyp hat, nehmen sowohl eingebaute Operatoren als auch benutzerdefinierte Operatorüberladungen an der Überladungsauflösung teil, wobei die Menge der Kandidatenfunktionen wie folgt ausgewählt wird:
Für einen unären Operator @, dessen Argument den Typ T1 hat (nach Entfernung von cv-Qualifizierern), oder für einen binären Operator @, dessen linkes Operand den Typ T1 und dessen rechtes Operand den Typ T2 hat (nach Entfernung von cv-Qualifizierern), werden die folgenden Mengen von Kandidatenfunktionen vorbereitet:
T1 eine vollständige Klasse oder eine gerade definierte Klasse ist, ist die Menge der Mitgliedskandidaten das Ergebnis einer qualifizierten Namenssuche von T1::operator@. In allen anderen Fällen ist die Menge der Mitgliedskandidaten leer.operator@ im Kontext des Ausdrucks gefunden werden (was ADL beinhalten kann), mit der Ausnahme, dass Mitgliedsfunktionsdeklarationen ignoriert werden und die Suche nicht daran hindern, in den nächsten umschließ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-Mitgliedskandidaten werden, diejenigen, deren Parameter diesen Aufzählungstyp haben (oder eine Referenz darauf).operator,, den unären operator& und operator-> ist die Menge der eingebauten Kandidaten leer. Für andere Operatoren sind eingebaute Kandidaten diejenigen, die auf den Seiten zu eingebauten Operatoren aufgeführt sind, vorausgesetzt, alle Operanden können implizit in ihre Parameter konvertiert werden. Wenn ein eingebauter Kandidat die gleiche Parameterliste wie ein Nicht-Mitgliedskandidat oder ein umgeschriebener Nicht-Mitgliedskandidat(seit C++20) hat, der keine Funktion-Template-Spezialisierung ist, wird er nicht zur Liste der eingebauten Kandidaten hinzugefügt. Wenn die eingebauten Zuweisungsoperatoren berücksichtigt werden, sind die Konversionen ihrer ersten Parameter eingeschränkt: Nur die Standard-Konversionssequenzen werden berücksichtigt.|
4) Umschriftkandidaten
In allen Fällen werden umgeschriebene Kandidaten nicht im Kontext des umgeschriebenen Ausdrucks berücksichtigt. Für alle anderen Operatoren ist die Menge der umgeschriebenen Kandidaten leer. |
(seit C++20) |
Die Menge der Kandidatenfunktionen, die der Überladungsauflösung unterbreitet werden, ist die Vereinigung der oben genannten Mengen. Die Argumentliste für den Zweck der Überladungsauflösung besteht aus den Operanden des Operators, mit Ausnahme von operator->, wo der zweite Operand kein Argument für den Funktionsaufruf ist (siehe Member-Access-Operator).
struct A { operator int(); // user-defined conversion }; A operator+(const A&, const A&); // non-member user-defined operator void m() { A a, b; a + b; // member-candidates: none // non-member candidates: operator+(a, b) // built-in candidates: int(a) + int(b) // overload resolution chooses operator+(a, b) }
Wenn die Überladungsauflösung einen eingebauten Kandidaten auswählt, ist die benutzerdefinierte Konversionssequenz von einem Operanden des Klassentyps nicht erlaubt, eine zweite Standard-Konversionssequenz zu haben: Die benutzerdefinierte Konversionsfunktion muss direkt den erwarteten Operandentyp liefern.
struct Y { operator int*(); }; // Y is convertible to int* int *a = Y() + 100.0; // error: no operator+ between pointer and double
Für operator,, den unären operator& und operator->, wenn im Satz der Kandidatenfunktionen keine gültigen Funktionen (siehe unten) vorhanden sind, wird der Operator als eingebaut neu interpretiert.
|
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 endgültigen Tiebreaker, der nicht umgeschriebene Kandidaten gegenüber umgeschriebenen Kandidaten 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) |
[edit] Initialisierung durch Konstruktor
Wenn ein Objekt eines Klassentyps direkt initialisiert oder standardmäßig initialisiert wird (einschließlich Standardinitialisierung im Kontext der Kopierlisteninitialisierung)(seit C++11), sind die Kandidatenfunktionen alle Konstruktoren der zu initialisierenden Klasse. Die Argumentliste ist die Ausdrucksliste des Initialisierers.
Andernfalls sind die Kandidatenfunktionen alle konvertierenden Konstruktoren der zu initialisierenden Klasse. Die Argumentliste ist der Ausdruck des Initialisierers.
|
Bei der Standardinitialisierung im Kontext der Kopierlisteninitialisierung, wenn ein |
(seit C++11) |
[edit] Kopierinitialisierung durch Konversion
Wenn die Kopierinitialisierung eines Objekts vom Klassentyp erfordert, dass eine benutzerdefinierte Konversion aufgerufen wird, um den Initialisierungs-Ausdruck vom Typ cv S in den Typ cv T des zu initialisierenden Objekts zu konvertieren, sind die folgenden Funktionen Kandidatenfunktionen:
- alle konvertierenden Konstruktoren von
T - die nicht-
explicitKonversionsfunktionen vonSund seinen Basisklassen (sofern nicht versteckt) nachToder einer vonTabgeleiteten Klasse oder einer Referenz darauf. Wenn diese Kopierinitialisierung Teil der direkten Initialisierungssequenz von cvTist (Initialisierung einer Referenz zur Bindung an den ersten Parameter eines Konstruktors, der eine Referenz auf cvTnimmt), dann werden auch explizite Konversionsfunktionen berücksichtigt.
In jedem Fall besteht die Argumentliste für den Zweck der Überladungsauflösung aus einem einzigen Argument, das der Initialisierungs-Ausdruck ist und gegen das erste Argument des Konstruktors oder gegen das implizite Objektargument der Konversionsfunktion verglichen wird.
[edit] Nicht-Klassen-Initialisierung durch Konversion
Wenn die Initialisierung eines Objekts vom Nicht-Klassentyp cv1 T eine benutzerdefinierte Konversionsfunktion erfordert, um von einem Initialisierungs-Ausdruck vom Klassentyp cv S zu konvertieren, sind die folgenden Funktionen Kandidaten:
- die nicht-expliziten benutzerdefinierten Konversionsfunktionen von
Sund seinen Basisklassen (sofern nicht versteckt), die den TypToder einen Typ, der durch eine Standard-Konversionssequenz inTkonvertierbar ist, oder eine Referenz auf einen solchen Typ erzeugen. cv-Qualifizierer auf dem Rückgabetyp werden für die Auswahl von Kandidatenfunktionen ignoriert. - Wenn dies eine direkte Initialisierung ist, werden auch die expliziten benutzerdefinierten Konversionsfunktionen von
Sund seinen Basisklassen (sofern nicht versteckt) berücksichtigt, die den TypToder einen Typ, der durch eine Qualifikationskonversion inTkonvertierbar ist, oder eine Referenz auf einen solchen Typ erzeugen.
In jedem Fall besteht die Argumentliste für den Zweck der Überladungsauflösung aus einem einzigen Argument, das der Initialisierungs-Ausdruck ist und gegen das implizite Objektargument der Konversionsfunktion verglichen wird.
[edit] Referenzinitialisierung durch Konversion
Bei der Referenzinitialisierung, bei der die Referenz auf cv1 T an das Lvalue- oder Rvalue-Ergebnis einer Konversion vom Initialisierungs-Ausdruck vom Klassentyp cv2 S gebunden wird, werden die folgenden Funktionen für den Kandidaten-Satz ausgewählt:
- Die nicht-expliziten benutzerdefinierten Konversionsfunktionen von
Sund seinen Basisklassen (sofern nicht versteckt) zum Typ
- (bei Konversion zu einem Lvalue) eine Lvalue-Referenz auf cv2
T2 - (bei Konversion zu einem Rvalue oder einem Lvalue vom Funktionstyp) cv2
T2oder eine Rvalue-Referenz auf cv2T2
- (bei Konversion zu einem Lvalue) eine Lvalue-Referenz auf cv2
- wobei cv2
T2referenzkompatibel mit cv1Tist.
- Bei direkter Initialisierung werden auch die expliziten benutzerdefinierten Konversionsfunktionen berücksichtigt, wenn
T2denselben Typ wieThat oder mit einer Qualifikationskonversion in den TypTkonvertiert werden kann.
In jedem Fall besteht die Argumentliste für den Zweck der Überladungsauflösung aus einem einzigen Argument, das der Initialisierungs-Ausdruck ist und gegen das implizite Objektargument der Konversionsfunktion verglichen wird.
[edit] Listeninitialisierung
Wenn ein Objekt vom nicht-aggregierten Klassentyp T listeninitialisiert wird, findet eine Zwei-Phasen-Überladungsauflösung statt.
- In Phase 1 sind die Kandidatenfunktionen alle Initializer-List-Konstruktoren von
Tund die Argumentliste für den Zweck der Überladungsauflösung besteht aus einem einzigen Initializer-List-Argument. - Wenn die Überladungsauflösung in Phase 1 fehlschlägt, wird Phase 2 eingeleitet, in der die Kandidatenfunktionen alle Konstruktoren von
Tsind und die Argumentliste für den Zweck der Überladungsauflösung aus den einzelnen Elementen der Initializer-Liste besteht.
Wenn die Initializer-Liste leer ist und T einen Standardkonstruktor hat, wird Phase 1 übersprungen.
Bei Kopierlisteninitialisierung, wenn Phase 2 einen expliziten Konstruktor wählt, ist die Initialisierung ill-formed (im Gegensatz zu allen anderen Kopierinitialisierungen, bei denen explizite Konstruktoren gar nicht berücksichtigt werden).
[edit] Zusätzliche Regeln für Funktion-Template-Kandidaten
Wenn die Namenssuche eine Funktion-Template findet, werden Template-Argument-Ableitung und die Prüfung aller expliziten Template-Argumente durchgeführt, um die Template-Argumentwerte (falls vorhanden) zu finden, die in diesem Fall verwendet werden können.
- Wenn beides erfolgreich ist, werden die Template-Argumente verwendet, um Deklarationen der entsprechenden Funktion-Template-Spezialisierungen zu synthetisieren, die zur Kandidatenmenge hinzugefügt werden, und solche Spezialisierungen werden genauso behandelt wie Nicht-Template-Funktionen, außer wo anders in den untenstehenden Tiebreaker-Regeln angegeben.
- Wenn die Argumentableitung fehlschlägt oder die synthetisierte Funktion-Template-Spezialisierung ill-formed wäre, wird keine solche Funktion zur Kandidatenmenge hinzugefügt (siehe SFINAE).
Wenn ein Name auf ein oder mehrere Funktion-Templates und auch auf eine Menge überladener Nicht-Template-Funktionen verweist, sind diese Funktionen und die aus den Templates generierten Spezialisierungen alle Kandidaten.
Weitere Details finden Sie unter Funktion-Template-Überladung.
|
Wenn ein Konstruktor-Template oder eine Konversionsfunktions-Template einen bedingten expliziten Spezifizierer hat, der wertabhängig ist, wird nach der Ableitung, wenn der Kontext einen Kandidaten erfordert, der nicht explizit ist, und die generierte Spezialisierung explizit ist, diese aus der Kandidatenmenge entfernt. |
(seit C++20) |
[edit] Zusätzliche Regeln für Konstruktor-Kandidaten
|
Standardmäßig deklarierte Move-Konstruktoren und Move-Zuweisungsoperatoren, die als gelöscht definiert sind, werden aus der Menge der Kandidatenfunktionen ausgeschlossen. Ein von der Klasse vom Typ
|
(seit C++11) |
[edit] Zusätzliche Regeln für Member-Funktions-Kandidaten
Wenn eine Kandidatenfunktion eine Memberfunktion ist (statisch oder nicht-statisch), die keinen expliziten Objektparameter hat(seit C++23), aber kein Konstruktor ist, 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 eigentlichen Parameter steht.
Ebenso wird das Objekt, auf dem eine Memberfunktion aufgerufen wird, als implizites Objektargument vor die Argumentliste gestellt.
Für Memberfunktionen der Klasse X beeinflusst der Typ des impliziten Objektparameters die cv-Qualifizierer und ref-Qualifizierer der Memberfunktion, wie in Memberfunktionen beschrieben.
Die benutzerdefinierten Konversionsfunktionen werden für die Bestimmung des Typs des impliziten Objektparameters als Member des impliziten Objektarguments betrachtet.
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 passend für jedes Objekt betrachtet: Sein Typ wird nicht geprüft und es wird keine Konversionssequenz dafür versucht. |
(bis C++23) |
Für den Rest der Überladungsauflösung ist das implizite Objektargument von anderen Argumenten nicht zu unterscheiden, aber die folgenden Sonderregeln gelten für den impliziten Objektparameter:
struct B { void f(int); }; struct A { operator B&(); }; A a; a.B::f(1); // Error: user-defined conversions cannot be applied // to the implicit object parameter static_cast<B&>(a).f(1); // OK
[edit] Gültige Funktionen
Gegeben die Menge der Kandidatenfunktionen, die wie oben beschrieben erstellt wurde, ist der nächste Schritt der Überladungsauflösung die Prüfung der Argumente und Parameter, um die Menge auf die Menge der gültigen Funktionen zu reduzieren.
Um in die Menge der gültigen Funktionen aufgenommen zu werden, muss die Kandidatenfunktion Folgendes erfüllen:
M Argumente gibt, ist die Kandidatenfunktion, die genau M Parameter hat, gültig.M Parameter hat, aber einen Ellipsenparameter hat, ist sie gültig.M Parameter hat und der M+1'ste Parameter und alle folgenden Parameter Standardargumente haben, ist sie gültig. Für den Rest der Überladungsauflösung wird die Parameterliste auf M gekürzt.|
4) Wenn die Funktion eine zugehörige Beschränkung hat, muss diese erfüllt sein.
|
(seit C++20) |
Benutzerdefinierte Konvertierungen (sowohl konvertierende Konstruktoren als auch benutzerdefinierte Konvertierungsfunktionen) dürfen nicht an impliziten Konvertierungssequenzen teilnehmen, wenn dies die Anwendung mehrerer benutzerdefinierter Konvertierungen 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 ist ein Kandidat für
- Kopierinitialisierung einer Klasse durch benutzerdefinierte Konvertierung,
- Initialisierung eines Nicht-Klassentyps durch eine Konvertierungsfunktion,
- Initialisierung durch Konvertierungsfunktion für direkte Referenzbindung,
- Initialisierung durch Konstruktor während des zweiten (Direktinitialisierungs-)Schritts der Kopierinitialisierung einer Klasse,
struct A { A(int); }; struct B { B(A); }; B b{{0}}; // list-initialization of B // candidates: B(const B&), B(B&&), B(A) // {0} -> B&& not viable: would have to call B(A) // {0} -> const B&: not viable: would have to bind to rvalue, would have to call B(A) // {0} -> A viable. Calls A(int): user-defined conversion to A is not banned |
(seit C++11) |
[edit] Beste aufrufbare Funktion
Für jedes Paar aufrufbarer Funktionen F1 und F2 werden die impliziten Konvertierungssequenzen vom i-ten Argument zum i-ten Parameter bewertet, um zu bestimmen, welche besser ist (mit Ausnahme des ersten Arguments, das implizite Objektargument für statische Memberfunktionen hat keinen Einfluss auf die Rangfolge)
F1 wird als bessere Funktion als F2 bestimmt, wenn die impliziten 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, wenn nicht das,F1 zum zu initialisierenden Typ besser als die Standardkonvertierungssequenz vom Ergebnis von F2, oder, wenn nicht das,|
3) (nur im Kontext der Initialisierung durch Konvertierungsfunktion für direkte Referenzbindung einer Referenz auf einen 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, wenn nicht das, |
(seit C++11) |
F1 ist eine Nicht-Templatenfunktion, während F2 eine Templatspezialisierung ist, oder, wenn nicht das,F1 und F2 sind beide Templatspezialisierungen und F1 ist gemäß den Regeln für die partielle Ordnung von Templatspezialisierungen stärker spezialisiert, oder, wenn nicht das,|
6)
F1 und F2 sind Nicht-Templatenfunktionen und F1 ist stärker partiell ordnungsbeschränkt als F2template<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, wenn nicht das,
|
(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 den gleichen Typstruct A { A(int = 0); }; struct B: A { using A::A; B(); }; B b; // OK, B::B() , oder, wenn nicht das,
|
(seit C++11) |
|
8)
F2 ist ein umgeschriebener Kandidat und F1 nicht, oder, wenn nicht das,9)
F1 und F2 sind beide umgeschriebene Kandidaten, und F2 ist ein synthetisierter umgeschriebener Kandidat mit umgekehrter Reihenfolge der Parameter und F1 nicht, oder, wenn nicht das, |
(seit C++20) |
|
10)
F1 wird aus einer benutzerdefinierten Deduktionsregel generiert und F2 nicht, oder, wenn nicht das,12)
F1 wird aus einem Nicht-Templatenkonstruktor generiert und F2 wird aus einem Konstruktor-Template generierttemplate<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 is A(A), the copy deduction candidate A x(1, 2, 3); // uses #3, generated from a non-template constructor template<class T> A(T) -> A<T>; // #6, less specialized than #5 A a (42); // uses #6 to deduce A<int> and #1 to initialize A b = a; // uses #5 to deduce A<int> and #2 to initialize template<class T> A(A<T>) -> A<A<T>>; // #7, as specialized as #5 A b2 = a; // uses #7 to deduce A<A<int>> and #1 to initialize |
(seit C++17) |
Diese paarweisen Vergleiche werden auf alle aufrufbaren Funktionen angewendet. Wenn genau eine aufrufbare Funktion besser ist als alle anderen, ist die Überladungsauflösung erfolgreich und diese Funktion wird aufgerufen. Andernfalls schlägt die Kompilierung fehl.
void Fcn(const int*, short); // overload #1 void Fcn(int*, int); // overload #2 int i; short s = 0; void f() { Fcn(&i, 1L); // 1st argument: &i -> int* is better than &i -> const int* // 2nd argument: 1L -> short and 1L -> int are equivalent // calls Fcn(int*, int) Fcn(&i, 'c'); // 1st argument: &i -> int* is better than &i -> const int* // 2nd argument: 'c' -> int is better than 'c' -> short // calls Fcn(int*, int) Fcn(&i, s); // 1st argument: &i -> int* is better than &i -> const int* // 2nd argument: s -> short is better than s -> int // no winner, compilation error }
Wenn die beste aufrufbare Funktion zu einer Funktion aufgelöst wird, für die mehrere Deklarationen gefunden wurden, und wenn zwei dieser Deklarationen sich in verschiedenen Geltungsbereichen befinden und ein Standardargument angeben, das die Funktion aufrufbar gemacht hat, ist das Programm schlecht geformt.
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, default argument was not used for viability f(); // error: found default argument twice }
[edit] Rangfolge impliziter Konvertierungssequenzen
Die bei der Überladungsauflösung berücksichtigten impliziten Konvertierungssequenzen von Argument zu Parameter entsprechen den impliziten Konvertierungen, die bei der Kopierinitialisierung (für Nicht-Referenzparameter) verwendet werden, mit der Ausnahme, dass bei 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 ist als jede andere Standardkonvertierungssequenz.(seit C++23)
Jeder Typ einer Standardkonvertierungssequenz erhält einen von drei Rängen
Der Rang der Standardkonvertierungssequenz ist der schlechteste der Ränge der Standardkonvertierungen, die sie enthält (es können bis zu drei Konvertierungen sein)
Die Bindung eines Referenzparameters direkt an den Argumentausdruck ist entweder eine Identität oder eine Konvertierung von abgeleitet zu Basis
struct Base {}; struct Derived : Base {} d; int f(Base&); // overload #1 int f(Derived&); // overload #2 int i = f(d); // d -> Derived& has rank Exact Match // d -> Base& has rank Conversion // calls f(Derived&)
Da die Rangfolge von Konvertierungssequenzen nur mit Typen und Wertkategorien arbeitet, kann ein Bitfeld für die Zwecke der Rangfolge an ein Referenzargument gebunden werden, aber wenn diese Funktion ausgewählt wird, ist sie schlecht geformt.
S1 ist besser als eine Standardkonvertierungssequenz S2, wennS1 eine echte Teilsequenz von S2 ist, unter Ausschluss von lvalue-Transformationen; die Identitätskonvertierungssequenz wird als Teilsequenz jeder Nicht-Identitätskonvertierung betrachtet, oder, wenn nicht das,S1 besser ist als der Rang von S2, oder, wenn nicht das,S1 und S2 an eine Referenz binden, die nicht der implizite Objektparameter einer ref-qualifizierten Memberfunktion ist, und S1 eine rvalue-Referenz an ein rvalue bindet, während S2 eine lvalue-Referenz an ein rvalue bindetint i; int f1(); int g(const int&); // overload #1 int g(const int&&); // overload #2 int j = g(i); // lvalue int -> const int& is the only valid conversion int k = g(f1()); // rvalue int -> const int&& better than rvalue int -> const int&
S1 und S2 an eine Referenz binden und S1 eine lvalue-Referenz auf eine Funktion bindet, während S2 eine rvalue-Referenz auf eine Funktion bindetint f(void(&)()); // overload #1 int f(void(&&)()); // overload #2 void g(); int i1 = f(g); // calls #1
S1 und S2 unterscheiden sich nur in der Qualifizierungs-Konvertierung, und|
die cv-Qualifizierung 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 nur Referenzparameter, die sich in der obersten cv-Qualifizierung unterscheiden, und der Typ von S1 ist weniger cv-qualifiziert als der von S2int f(const int &); // overload #1 int f(int &); // overload #2 (both references) int g(const int &); // overload #1 int g(int); // overload #2 int i; int j = f(i); // lvalue i -> int& is better than lvalue int -> const int& // calls f(int&) int k = g(i); // lvalue i -> const int& ranks Exact Match // lvalue i -> rvalue int ranks Exact Match // ambiguous overload: compilation error
S1 und S2 binden den gleichen Referenztyp "Referenz auf T" und haben die Quelltypen V1 und 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&(); // overload #1 }; struct B { operator Z(); operator const Z&&(); // overload #2 }; const Z& r1 = A(); // OK, uses #1 const Z&& r2 = B(); // OK, uses #2
U1 ist besser als eine benutzerdefinierte Konvertierungssequenz U2, wenn sie den gleichen Konstruktor/die gleiche 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 U2struct 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 eine 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 eine Listeninitialisierungssequenz L2, wenn die entsprechenden Parameter Referenzen auf Arrays sind und L1 in den Typ "Array von N1 T" konvertiert, L2 in den Typ "Array von N2 T" und N1 kleiner als N2 ist. |
(seit C++11) (bis C++20) |
|
6) Eine Listeninitialisierungssequenz L1 ist besser als eine Listeninitialisierungssequenz L2, wenn die entsprechenden Parameter Referenzen auf Arrays sind und L1 und L2 in 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 |
(seit C++20) |
Wenn zwei Konvertierungssequenzen aufgrund des gleichen Rangs ununterscheidbar sind, gelten die folgenden zusätzlichen Regeln
|
2) Eine Konvertierung, die eine Aufzählung, deren zugrundeliegender Typ festgelegt ist, zu ihrem zugrundeliegenden Typ befördert, ist besser als eine, die zum beförderten zugrundeliegenden Typ befördert, wenn die beiden Typen unterschiedlich sind.
enum num : char { one = '0' }; std::cout << num::one; // '0', not 48 |
(seit C++11) |
|
3) Eine Konvertierung in eine beliebige Richtung zwischen einem Gleitkommatyp
FP1 und einem Gleitkommatyp FP2 ist besser als eine Konvertierung in die gleiche Richtung zwischen FP1 und einem arithmetischen 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 von Base abgeleitet ist (direkt oder indirekt) und Derived von Mid abgeleitet istDerived* zu Mid* ist besser als Derived* zu Base*Derived zu Mid& oder Mid&& ist besser als Derived zu Base& oder Base&&Base::* zu Mid::* ist besser als Base::* zu Derived::*Derived zu Mid ist besser als Derived zu BaseMid* zu Base* ist besser als Derived* zu Base*Mid zu Base& oder Base&& ist besser als Derived zu Base& oder Base&&Mid::* zu Derived::* ist besser als Base::* zu Derived::*Mid zu Base ist besser als Derived zu BaseMehrdeutige Konvertierungssequenzen werden als benutzerdefinierte Konvertierungssequenzen eingestuft, da für ein Argument nur dann mehrere Konvertierungssequenzen existieren können, wenn sie unterschiedliche benutzerdefinierte Konvertierungen beinhalten
class B; class A { A (B&);}; // converting constructor class B { operator A (); }; // user-defined conversion function class C { C (B&); }; // converting constructor void f(A) {} // overload #1 void f(C) {} // overload #2 B b; f(b); // B -> A via ctor or B -> A via function (ambiguous conversion) // b -> C via ctor (user-defined conversion) // the conversions for overload #1 and for overload #2 // are indistinguishable; compilation fails
[edit] Implizite Konvertierungssequenz bei Listeninitialisierung
Bei der Listeninitialisierung ist das Argument eine braced-init-list, die kein Ausdruck ist, sodass die implizite Konvertierungssequenz in den Parametertyp zum Zwecke der Überladungsauflösung durch die folgenden Sonderregeln bestimmt wird
- Wenn der Parametertyp ein Aggregat
Xist und die Initialisierungsliste aus genau einem Element desselben oder abgeleiteten Typs (möglicherweise cv-qualifiziert) besteht, ist die implizite Konvertierungssequenz diejenige, die zur Konvertierung des Elements in den Parametertyp erforderlich ist. - Andernfalls, wenn der Parametertyp eine Referenz auf ein Zeichenarray ist und die Initialisierungsliste ein einzelnes Element enthält, das ein Zeichenkettenliteral des entsprechenden Typs ist, ist die implizite Konvertierungssequenz die Identitätskonvertierung.
- Andernfalls, wenn der Parametertyp std::initializer_list<X> ist und eine nicht-verengende implizite Konvertierung von jedem Element der Initialisierungsliste nach
Xexistiert, ist die implizite Konvertierungssequenz für die Überladungsauflösung die schlechteste erforderliche Konvertierung. Wenn die braced-init-list 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}; // selects #1 (rvalue double -> double: identity conv) void g(A); g({"foo", "bar"}); // selects #3 (lvalue const char[4] -> std::string: user-def conv)
- Andernfalls, wenn der Parametertyp "Array von N T" ist (dies geschieht nur für Referenzen auf Arrays), muss die Initialisierungsliste N oder weniger Elemente enthalten, und die schlechteste implizite Konvertierung, die erforderlich ist, um jedes Element der Liste (oder das leere Klammerpaar
{}, wenn die Liste kürzer als N ist) inTzu konvertieren, wird verwendet.
|
(seit C++20) |
typedef int IA[3]; void h(const IA&); void g(int (&&)[]); h({1, 2, 3}); // int->int identity conversion g({1, 2, 3}); // same as above since C++20
- Andernfalls, wenn der Parametertyp ein Nicht-Aggregat-Klassentyp
Xist, wählt die Überladungsauflösung den Konstruktor C von X aus, um aus der Argumentinitialisierungsliste zu initialisieren
- Wenn C kein Initialisierungslisten-Konstruktor ist und die Initialisierungsliste ein einzelnes Element vom möglicherweise cv-qualifizierten X enthält, hat die implizite Konvertierungssequenz den Rang "Exakte Übereinstimmung". Wenn die Initialisierungsliste ein einzelnes Element eines möglicherweise cv-qualifizierten Typs enthält, der von X abgeleitet ist, hat die implizite Konvertierungssequenz den Rang "Konvertierung". (beachten Sie den Unterschied zu Aggregaten: Aggregate werden direkt aus einteiligen Initialisierungslisten initialisiert, bevor die Aggregatinitialisierung berücksichtigt wird; Nicht-Aggregate berücksichtigen Initialisierungslisten-Konstruktoren vor allen anderen Konstruktoren)
- andernfalls ist die implizite Konvertierungssequenz eine benutzerdefinierte Konvertierungssequenz mit der zweiten Standardkonvertierungssequenz als Identitätskonvertierung.
Wenn mehrere Konstruktoren aufrufbar sind, aber keiner besser ist als die anderen, 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'}); // calls g(B(int, double)), user-defined conversion // g({1.0, 1,0}); // error: double->int is narrowing, not allowed in list-init void f(B); // f({'a', 'b'}); // f(A) and f(B) both user-defined conversions
- Andernfalls, wenn der Parametertyp ein Aggregat ist, das gemäß den Regeln für die Aggregatinitialisierung aus der Initialisierungsliste initialisiert werden kann, ist die implizite Konvertierungssequenz eine benutzerdefinierte Konvertierungssequenz, deren zweite Standardkonvertierungssequenz eine Identitätskonvertierung ist.
struct A { int m1; double m2; }; void f(A); f({'a', 'b'}); // calls f(A(int, double)), user-defined conversion
- Andernfalls gelten die Regeln für die Referenzinitialisierung, wenn der Parameter eine Referenz ist
struct A { int m1; double m2; }; void f(const A&); f({'a', 'b'}); // temporary created, f(A(int, double)) called. User-defined conversion
- Andernfalls, wenn der Parametertyp keine Klasse ist und die Initialisierungsliste ein Element hat, ist die implizite Konvertierungssequenz diejenige, die zur Konvertierung des Elements in den Parametertyp erforderlich ist
- Andernfalls, wenn der Parametertyp kein Klassentyp ist und die Initialisierungsliste keine Elemente hat, ist die implizite Konvertierungssequenz die Identitätskonvertierung.
|
Wenn das Argument eine benannte Initialisierungsliste 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 die Aggregatinitialisierung aus dieser benannten Initialisierungsliste initialisiert werden kann, in diesem Fall ist die implizite Konvertierungssequenz eine benutzerdefinierte Konvertierungssequenz, deren zweite Standardkonvertierungssequenz eine Identitätskonvertierung ist. Wenn nach der Überladungsauflösung die Reihenfolge der Deklaration der Mitglieder des Aggregats für die ausgewählte Überladung nicht übereinstimmt, ist die Initialisierung des Parameters schlecht geformt. 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) |
[edit] 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 1 | C++98 | das Verhalten war undefiniert, wenn die gleiche Funktion mit möglicherweise unterschiedlichen Standard Argumenten (aus verschiedenen Geltungsbereichen) ausgewählt wird |
das Programm ist schlecht ge- formt in diesem Fall |
| CWG 83 | C++98 | die Konvertierungssequenz von einem String-Literal zu char* war besser als die zu const char* obwohl erstere veraltet ist |
der Rang der veralteten Konvertierung wird gesenkt (er wurde in C++11 entfernt) |
| CWG 162 | C++98 | es war ungültig, wenn das durch F benannte Überladungsseteine nicht-statische Memberfunktion im Fall von &F(args) enthält |
nur ungültig, wenn die Überladungs- auflösung eine nicht-statische Memberfunktion in diesem Fall auswählt |
| CWG 233 | C++98 | Referenzen und Zeiger wurden inkonsistent behandelt bei der Überladungsauflösung mit benutzerdefinierten Konvertierungen |
sie werden konsistent behandelt |
| CWG 280 | C++98 | Surrogat-Aufruffunktionen wurden nicht zu der Menge der Kandidatenfunktionen für Konvertierungs- funktionen hinzugefügt, die in unzugänglichen Basisklassen deklariert sind |
die Zugänglichkeitsbeschränkung entfernt, das Programm ist schlecht geformt, wenn eine Surrogat-Aufruf- Funktion ausgewählt wird und die entsprechende Konvertierungs- Funktion nicht aufgerufen werden kann CWG 415 |
| wenn eine Funktion-Template als Kandidat ausgewählt wurde, | C++98 | wurden ihre Spezialisierungen mittels Template-Argumentdeduktion instanziiert keine Instanziierung wird in |
diesem Fall stattfinden, ihre Deklarationen werden synthetisiert CWG 495 |
| wenn die impliziten Konvertierungen für Argumente gleich | C++98 | gut waren, war eine Nicht-Template-Konvertierungsfunktion immer besser als eine Konvertierungsfunktions-Vorlage, auch wenn letztere eine bessere Standardkonvertierungssequenz haben könnte Standardkonvertierungs- |
sequenzen werden verglichen vor Spezialisierungsebenen CWG 1307 |
| Die Überladungsauflösung basierend auf der Array-Größe war nicht spezifiziert | C++11 | ein kürzeres Array ist | besser, wenn möglich CWG 1328 |
| Die Bestimmung der Kandidatenfunktionen beim | C++11 | Binden einer Referenz an ein Konvertierungsergebnis war unklar CWG 1374 |
wurde klargestellt |
| Qualifizierungs-Konvertierung wurde vor Referenz- | C++98 | bindung beim Vergleich von Standardkonvertierungssequenzen geprüft |
umgekehrt |
| CWG 1385 | C++11 | Eine nicht-explizite benutzerdefinierte Konvertierungsfunktion, deklariert mit einem Ref-Qualifizierer, hatte keine entsprechende Surrogat-Funktion |
sie hat eine entsprechende Surrogat-Funktion |
| CWG 1467 | C++11 | gleichtypige Listeninitialisierung von Aggregaten und Arrays wurde weggelassen |
Initialisierung definiert |
| CWG 1601 | C++11 | Konvertierung von Enum zum zugrundeliegenden Typ bevorzugte nicht den festgelegten zugrundeliegenden Typ |
der festgelegte Typ wird bevorzugt gegenüber dem, zu dem er befördert wird |
| CWG 1608 | C++98 | Die Menge der Memberkandidaten eines unären Operators @dessen Argument den Typ T1 hat, war leer, wennT1 eine Klasse ist, die gerade definiert wird |
die Menge ist das Ergebnis der qualifizierten Namensauflösung von T1::operator@ in diesem Fall |
| CWG 1687 | C++98 | Wenn ein integrierter Kandidat durch Überladungsauflösung ausgewählt wurde, würden die Operanden ohne Einschränkung konvertiert werden |
konvertiert nur Klassenoperanden, und deaktiviert die zweite Standardkonvertierungssequenz |
| CWG 2052 | C++98 | schlecht geformte synthetisierte Funktion-Template-Spezialisierungen könnten zur Kandidatenmenge hinzugefügt werden, wodurch das Programm schlecht geformt wird |
sie werden nicht hinzugefügt zur Kandidatenmenge |
| CWG 2076 | C++11 | Benutzerdefinierte Konvertierung wird auf den einzelnen Initialisierer angewendet in einer verschachtelten Initialisierungsliste während der Listeninitialisierung aufgrund der Auflösung von CWG-Problem 1467 |
nicht angewendet |
| CWG 2137 | C++11 | Initialisierungslisten-Konstruktoren gingen für Kopier- Konstruktoren bei der Listeninitialisierung von X aus {X} verloren |
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 | Integrierte Kandidaten mit der gleichen Parameter- liste wie ein umgeschriebener Nicht-Member-Kandidat wurden zur Liste der integrierten Kandidaten hinzugefügt |
nicht hinzugefügt |
| CWG 2712 | C++98 | Wenn ein integrierter Zuweisungsoperator berücksichtigt wurde, konnte der erste Parameter nicht an ein Temporäres gebunden werden, was bereits unmöglich ist[1] |
entfernte die redundante Anforderung |
| CWG 2713 | C++20 | Die Konvertierungsbeschränkung bezüglich benannter Initialisierungs- Listen wurde auch dann angewendet, wenn der Parameter eine Referenz ist |
in diesem Fall nicht eingeschränkt |
| CWG 2789 | C++23 | Der explizite Objektparameter wurde bei Vergleichen von Parameter-Typ-Listen einbezogen |
ausgeschlossen |
| CWG 2856 | C++11 | Die Überladungsauflösung für die Standardinitialisierung im Kontext der Kopier-Listen-Initialisierung berücksichtigte nur konvertierende Konstruktoren |
berücksichtigt alle Konstruktoren |
| CWG 2919 | C++98 | Die Kandidatenmenge für Referenzinitialisierung durch Konvertierung hing vom Zieltyp der Initialisierung ab |
hängt vom Ziel- Typ der Konvertierung ab |
| P2468R2 | C++20 | Umgeschriebene Kandidaten basierend auf operator== werden hinzugefügt für a != b auch wenn ein passender operator!= existiert |
nicht hinzugefügt |
- ↑ Der Typ des ersten Parameters eines integrierten Zuweisungsoperators ist „lvalue-Referenz auf möglicherweise volatile qualifiziertes
T“. Referenzen dieses Typs können nicht an ein Temporäres gebunden werden.
[edit] Referenzen
- C++23 Standard (ISO/IEC 14882:2024)
- 12.2 Überladungsauflösung [over.match]
- C++20 Standard (ISO/IEC 14882:2020)
- 12.4 Überladungsauflö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 Überladungsauflösung [over.match]