Namespaces
Variants

Overload resolution

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

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:

  1. Erstellen der Menge der Kandidatenfunktionen .
  2. Reduzieren der Menge auf nur geeignete Funktionen .
  3. 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 ).

Inhaltsverzeichnis

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 T besitzt), dann wird B als Memberfunktion von T gesucht. Die durch diese Suche gefundenen Funktionsdeklarationen sind die Kandidatenfunktionen. Die Argumentliste für die Überlagerungsauflösung enthält das implizite Objektargument vom Typ cv T .
  • 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 auf T oder eine abgeleitete Klasse von T zeigt, * this als implizites Objektargument verwendet wird. Andernfalls (wenn this nicht im Gültigkeitsbereich ist oder nicht auf T zeigt), wird ein Pseudo-Objekt vom Typ T als 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 T werden 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- explicit benutzerdefinierte Konvertierungsfunktion in T oder in einer Basisklasse von T (sofern nicht verborgen), deren CV-Qualifizierer gleich oder stärker als die CV-Qualifizierer von T sind, 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:

1) Mitgliederkandidaten : wenn 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.
2) non-member candidates : Für Operatoren, bei denen operator overloading nicht-Member-Formen erlaubt, alle Deklarationen, die durch unqualified name lookup von 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.
3) eingebaute Kandidaten : Für operator, , den unären operator & , und operator - > , ist die Menge der eingebauten Kandidaten leer. Für andere Operatoren sind die eingebauten Kandidaten diejenigen, die in den eingebauten Operator-Seiten aufgelistet sind, sofern alle Operanden implizit in ihre Parameter konvertiert werden können. Wenn ein eingebauter Kandidat dieselbe Parameterliste wie ein Nicht-Mitglied-Kandidat oder umgeschriebener Nicht-Mitglied-Kandidat (seit C++20) hat, der keine Funktions-Templatespezialisierung ist, wird er nicht zur Liste der eingebauten Kandidaten hinzugefügt. Wenn die eingebauten Zuweisungsoperatoren betrachtet werden, sind die Konvertierungen von ihren ersten Parametern eingeschränkt: Es werden nur Standardkonvertierungssequenzen berücksichtigt.
4) umgeschriebene Kandidaten :
  • Für die vier relationalen Operatorausdrücke x < y , x <= y , x > y und x >= y werden alle gefundenen Member-, Non-Member- und Built-in operator <=> s zur Menge hinzugefügt.
  • Für die vier relationalen Operatorausdrücke x < y , x <= y , x > y und x >= y sowie den Drei-Wege-Vergleichsausdruck x <=> y wird für jeden gefundenen Member-, Non-Member- und Built-in operator <=> ein synthetisierter Kandidat mit umgekehrter Parameterreihenfolge hinzugefügt.
  • Für x ! = y werden alle gefundenen Member-, Non-Member- und Built-in operator == s zur Menge hinzugefügt, sofern kein passender operator ! = existiert.
  • Für Gleichheitsoperatorausdrücke x == y und x ! = y wird für jeden gefundenen Member-, Non-Member- und Built-in operator == ein synthetisierter Kandidat mit umgekehrter Parameterreihenfolge hinzugefügt, sofern kein passender operator ! = existiert.
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 @ ausgewählt wird, wird x @ y als umgeschriebener Ausdruck interpretiert: 0 @ ( y <=> x ) falls der ausgewählte Kandidat ein synthetisierter Kandidat mit umgekehrter Parameterreihenfolge ist, oder ( x <=> y ) @ 0 andernfalls, unter Verwendung des ausgewählten umgeschriebenen operator <=> -Kandidaten.

Wenn ein umgeschriebener operator == -Kandidat durch Überladungsauflösung für einen Operator @ (welcher entweder == oder != ist) ausgewählt wird, muss sein Rückgabetyp (möglicherweise cv-qualifiziert) bool sein, und x @ y wird als umgeschriebener Ausdruck interpretiert: y == x oder ! ( y == x ) falls der ausgewählte Kandidat ein synthetisierter Kandidat mit umgekehrter Parameterreihenfolge ist, oder ! ( x == y ) andernfalls, unter Verwendung des ausgewählten umgeschriebenen operator == -Kandidaten.

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 explicit Konstruktor ausgewählt wird, ist die Initialisierung fehlerhaft.

(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- explicit Konvertierungsfunktionen von S und seinen Basisklassen (sofern nicht verborgen) zu T oder einer von T abgeleiteten Klasse oder einer Referenz darauf. Wenn diese Kopierinitialisierung Teil der Direktinitialisierungssequenz von cv T ist (Initialisierung einer Referenz, die an den ersten Parameter eines Konstruktors gebunden werden soll, der eine Referenz auf cv T nimmt), 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 S und seinen Basisklassen (sofern nicht verborgen), die Typ T oder einen durch eine Standardkonvertierungssequenz konvertierbaren Typ zu T erzeugen, 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 S und seinen Basisklassen (sofern nicht verborgen) berücksichtigt, die Typ T oder einen durch eine Qualifikationskonvertierung konvertierbaren Typ zu T erzeugen, 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 S und 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 T2 oder Rvalue-Referenz auf cv2 T2
wobei cv2 T2 referenzkompatibel mit cv1 T ist.
  • Für die direkte Initialisierung werden auch explizite benutzerdefinierte Konvertierungsfunktionen berücksichtigt, wenn T2 denselben Typ wie T aufweist oder durch eine Qualifikationskonvertierung in den Typ T umgewandelt 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 T und 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 T sind 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 C geerbter Konstruktor , dessen erster Parameter vom Typ "Referenz auf P " ist (einschließlich eines solchen Konstruktors, der aus einem Template instanziiert wurde), wird aus der Menge der Kandidatenfunktionen ausgeschlossen, wenn ein Objekt vom Typ D erstellt wird und alle folgenden Bedingungen erfüllt sind:

  • Die Argumentliste hat genau ein Argument.
  • C ist referenzverwandt mit P .
  • P ist referenzverwandt mit D .
(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 :

1) benutzerdefinierte Konvertierungen können nicht auf den impliziten Objektparameter angewendet werden
2) Rvalues können an nicht-konstante implizite Objektparameter gebunden werden (sofern es sich nicht um eine ref-qualifizierte Memberfunktion handelt) (seit C++11) und beeinflussen das Ranking der impliziten Konvertierungen nicht.
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:

1) Wenn es M Argumente gibt, ist die Kandidatenfunktion, die genau M Parameter hat, geeignet
2) Wenn die Kandidatenfunktion weniger als M Parameter hat, aber einen Ellipsenparameter besitzt, ist sie verwendbar.
3) Wenn die Kandidatenfunktion mehr als 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)
5) Für jedes Argument muss mindestens eine implizite Konvertierungssequenz existieren, die es in den entsprechenden Parameter umwandelt.
6) Wenn ein Parameter Referenztyp hat, wird die Referenzbindung in diesem Schritt berücksichtigt: Wenn ein Rvalue-Argument einem nicht-konstanten Lvalue-Referenzparameter entspricht oder ein Lvalue-Argument einem Rvalue-Referenzparameter entspricht, ist die Funktion nicht geeignet.

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

  • Initialisierung durch Listeninitialisierung, bei der die Initialisierungsliste genau ein Element enthält, das selbst eine Initialisierungsliste ist, und das Ziel der erste Parameter eines Konstruktors der Klasse X ist, und die Konvertierung zu X oder Referenz auf (möglicherweise cv-qualifiziertes) X erfolgt:
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

1) es gibt mindestens ein Argument von F1 , dessen implizite Konvertierung besser ist als die entsprechende implizite Konvertierung für dieses Argument von F2 , oder, falls nicht zutreffend,
2) (nur im Kontext der Nicht-Klassen-Initialisierung durch Konvertierung), die Standardkonvertierungssequenz vom Ergebnis von 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)
4) F1 ist eine Nicht-Template-Funktion, während F2 eine Template-Spezialisierung ist, oder, falls nicht,
5) 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,
11) F1 ist der Kopierdeduktionskandidat und F2 ist es 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:

1) Exakte Übereinstimmung : keine Konvertierung erforderlich, Lvalue-zu-Rvalue-Konvertierung, Qualifikationskonvertierung, Funktionszeigerkonvertierung, (seit C++17) benutzerdefinierte Konvertierung von Klassentyp zur gleichen Klasse
2) Promotion : Integral-Promotion, Gleitkomma-Promotion
3) Konvertierung : Ganzzahlkonvertierung, Gleitkommakonvertierung, Ganzzahl-Gleitkomma-Konvertierung, Zeigerkonvertierung, Zeiger-auf-Mitglied-Konvertierung, boolesche Konvertierung, benutzerdefinierte Konvertierung einer abgeleiteten Klasse zu ihrer Basisklasse

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.

1) Eine Standardkonvertierungssequenz ist immer besser als eine benutzerdefinierte Konvertierungssequenz oder eine Ellipsen-Konvertierungssequenz.
2) Eine benutzerdefinierte Konvertierungssequenz ist immer besser als eine Ellipsen-Konvertierungssequenz .
3) Eine Standardkonvertierungssequenz S1 ist besser als eine Standardkonvertierungssequenz S2 wenn
a) 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,
b) der Rang von S1 ist besser als der Rang von S2 , oder, falls nicht,
c) sowohl 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&
oder, falls nicht das,
d) beide 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
oder, falls nicht das,
e) S1 und S2 unterscheiden sich nur in der Qualifikationskonvertierung, und

die CV-Qualifikation des Ergebnisses von S1 ist eine echte Teilmenge der CV-Qualifikation des Ergebnisses von S2 , und S1 ist nicht die veraltete String-Literal-Array-zu-Pointer-Konvertierung (bis C++11) .

(bis C++20)

das Ergebnis von S1 kann in das Ergebnis von S2 durch eine Qualifikationskonvertierung umgewandelt werden.

(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*)
oder, falls nicht das,
f) beide 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
oder, falls nicht das,
g) 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
4) Eine benutzerdefinierte Konvertierungssequenz 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)
5) Eine Listeninitialisierungssequenz 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
  • die Anzahl der durch L1 initialisierten Elemente N1 kleiner ist als die Anzahl der durch L2 initialisierten Elemente N2, oder
  • N1 gleich N2 ist und L2 zu einem Array unbekannter Größe konvertiert und L1 nicht.
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:

1) Eine Konvertierung, die keinen Zeiger auf bool oder Zeiger-auf-Mitglied zu bool beinhaltet, ist besser als eine, die dies tut.
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)
4) Die Konvertierung, die einen Zeiger-auf-abgeleitete-Klasse in einen Zeiger-auf-Basisklasse umwandelt, ist besser als die Konvertierung von Zeiger-auf-abgeleitete-Klasse in Zeiger-auf- void , und die Konvertierung von Zeiger-auf-Basisklasse in void ist besser als Zeiger-auf-abgeleitete-Klasse in void .
5) Wenn Mid (direkt oder indirekt) von Base abgeleitet ist, und Derived (direkt oder indirekt) von Mid abgeleitet ist
a) Derived * zu Mid * ist besser als Derived * zu Base *
b) Derived nach Mid & oder Mid && ist besser als Derived nach Base & oder Base &&
c) Base :: * nach Mid :: * ist besser als Base :: * nach Derived :: *
d) Derived zu Mid ist besser als Derived zu Base
e) Mid * zu Base * ist besser als Derived * zu Base *
f) Mid nach Base & oder Base && ist besser als Derived nach Base & oder Base &&
g) Mid :: * zu Derived :: * ist besser als Base :: * zu Derived :: *
h) 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 X ist 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 X gibt, 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) zu T zu konvertieren, wird verwendet.
  • Andernfalls, wenn der Parametertyp "Array unbekannter Grenze von T" ist (dies tritt nur bei Referenzen auf Arrays auf), wird die schlechteste implizite Konvertierung verwendet, die notwendig ist, um jedes Element der Liste in T zu konvertieren.
(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 X ist, 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
  1. 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]

Siehe auch