Betrachten Sie diesen Code:
#include <vector>
#include <iostream>
enum class A
{
X, Y
};
struct Test
{
Test(const std::vector<double>&, const std::vector<int>& = {}, A = A::X)
{ std::cout << "vector overload" << std::endl; }
Test(const std::vector<double>&, int, A = A::X)
{ std::cout << "int overload" << std::endl; }
};
int main()
{
std::vector<double> v;
Test t1(v);
Test t2(v, {}, A::X);
}
Dies druckt:
vector overload
int overload
Warum führt dies nicht zu einem Kompilierungsfehler aufgrund einer mehrdeutigen Überlastungsauflösung? Wenn der zweite Konstruktor entfernt wird, erhalten wir vector overload
zwei Mal. Wie / nach welcher Metrik passt int
eine eindeutig bessere Übereinstimmung {}
als std::vector<int>
?
Die Konstruktorsignatur kann sicherlich weiter gekürzt werden, aber ich wurde gerade von einem äquivalenten Code ausgetrickst und möchte sicherstellen, dass für diese Frage nichts Wichtiges verloren geht.
c++
language-lawyer
overload-resolution
Max Langhof
quelle
quelle
{}
als Codeblock erinnere , weist ich Variablen 0 zu - Beispiel: const char x = {}; wird auf 0 (null Zeichen) gesetzt, dasselbe gilt für int usw.{}
in bestimmten Sonderfällen effektiv funktioniert, aber es ist im Allgemeinen nicht korrekt (für den Anfang,std::vector<int> x = {};
funktioniert,std::vector <int> x = 0;
funktioniert nicht). Es ist nicht so einfach wie "{}
Null zuweisen".struct A { int x = 5; }; A a = {};
weist in keiner Weise Null zu, sondern erstellt eineA
mita.x = 5
. Dies ist anders alsA a = { 0 };
bei der Initialisierunga.x
auf 0. Die Null ist nicht inhärent{}
, sondern inhärent, wie jeder Typ standardmäßig konstruiert oder wertinitialisiert ist. Sehen Sie hier , hier und hier .Antworten:
Es ist in [over.ics.list] , Hervorhebung von mir
Das
std::vector
wird vom Konstruktor initialisiert und das fettgedruckte Aufzählungszeichen hält es für eine benutzerdefinierte Konvertierung. In der Zwischenzeit istint
dies die Identitätsumwandlung, sodass der Rang des ersten C'tors übertroffen wird.quelle
0
hat Typ,int
aber keinen Typstd::vector<int>
, wie ist das ein "als ob" für die "untypisierte" Natur von{}
?std::vector<int>
. Wie Sie sagten, habe ich erwartet, dass "der Typ des Parameters letztendlich entscheidet, was der Typ des Arguments ist", und ein{}
"Typ" (sozusagen)std::vector<int>
sollte keine (Nichtidentitäts-) Konvertierung benötigen, um a zu initialisierenstd::vector<int>
. Der Standard sagt es offensichtlich, also ist das das, aber es macht für mich keinen Sinn. (Wohlgemerkt, ich behaupte nicht, dass Sie oder der Standard falsch sind, sondern versuche nur, dies mit meinen mentalen Modellen in Einklang zu bringen.)