IMHO Ich glaube, dass GCC falsch ist und CLANG ist hier richtig. Ich werde versuchen, meinen Anspruch unten zu rechtfertigen:
Nach der Norm §14.8.3/p1 Überlast Auflösung [temp.over] (Hervorhebung von mir):
Eine Funktion Vorlage kann entweder durch (nicht Vorlage) Funktionen seines Namens oder durch (andere) Funktionsvorlagen desselben Namens überladen werden. Wenn ein Aufruf dieses Namens geschrieben wird (explizit oder implizit unter Verwendung der Operatornotation), Vorlage Argumentabzug (14.8.2) und Überprüfung der expliziten Vorlage Argumente (14.3) werden für jede Funktionsvorlage durchgeführt, um die zu finden Vorlagenargumentwerte (wenn any), die mit dieser Funktionsvorlage verwendet werden können, um eine Funktionsschablonenspezialisierung zu instanziieren, die mit den Aufrufargumenten aufgerufen werden kann. Für jede Funktionsvorlage, wenn der Argumentabzug und Überprüfung erfolgreich ist, werden die Template-Argumente (abgeleitet und/oder explizit) verwendet, um die Deklaration einer einzelnen Funktion Vorlage Spezialisierung, die zu den Kandidaten-Funktionen auf gesetzt ist, zu ergänzen in Überladungsauflösung verwendet. Wenn für eine gegebene Funktionsvorlage Argumentabzug fehlschlägt oder die synthetisierte Funktionsschablone Spezialisierung schlecht gebildet wäre, wird keine solche Funktion zum Satz von Kandidatenfunktionen für diese Vorlage hinzugefügt. Der vollständige Satz von Kandidatenfunktionen umfasst alle synthetisierten Deklarationen und alle der nicht überladenen Funktionen mit dem gleichen Namen. Die synthetisierten Deklarationen werden wie alle anderen Funktionen in der Rest der Überladungsauflösung behandelt, außer wie explizit in 13.3.3 erwähnt.
[Beispiel:
template<class T> T max(T a, T b) { return a>b?a:b; }
void f(int a, int b, char c, char d) {
int m1 = max(a,b); // max(int a, int b)
char m2 = max(c,d); // max(char a, char b)
int m3 = max(a,c); // error: cannot generate max(int,char)
}
144) Die Parameter der Funktionsschablone Spezialisierungen enthalten keine Parametertypen Vorlage. Der Satz von Konvertierungen, die auf abgeleiteten -Argumenten erlaubt sind, ist begrenzt, da der Argumentabzugsprozess Funktionsschablonen mit Parametern erzeugt, die entweder exakt dem Aufruf entsprechen oder sich nur in den Möglichkeiten unterscheiden, die durch die zulässigen begrenzten Konvertierungen überbrückt werden können.Nicht-abgeleitete Argumente ermöglichen die vollständige Bandbreite von Konvertierungen. Beachten Sie auch, dass 13.3.3 angibt, dass eine Nicht-Vorlage-Funktion gegenüber einer Vorlage Spezialisierung bevorzugt wird, wenn die beiden Funktionen ansonsten gleich gute Kandidaten für eine Überladungsübereinstimmung sind.
Aus der obigen wir bekommen, dass explizite Template-Argumente überprüft, und wenn Prüfung erfolgreich verläuft dann verwendet werden, um eine Spezialisierung zu synthetisieren, die für die Überladungsauflösung für die Kandidaten Funktionen hinzugefügt werden. Daher ist die Tatsache, dass Sie explizit X
angeben, für den Prozess irrelevant.
Auch aus dem C++ Standard §13.3.3/P1.7 Beste tragfähige Funktion [over.match.best]:
F1
und F2
sind Funktions-Template Spezialisierungen und die Funktion Vorlage für F1
ist spezialisierter als die Vorlage für F2
gemäß den Teilordnungsregeln, die in 14.5.6.2 beschrieben sind.
Jetzt von §14.5.6.2/p3 Teil Bestellung von Funktionsschablonen [temp.func.order] wir bekommen, dass in Teilordnungsparameter Packs auch ins Spiel sind, also kein Problem auch hier. Jetzt
:
template <typename X, typename... T>
auto bar(int, T...) -> void;
ist spezialisierter als:
template <typename X, typename Check, typename... T>
auto bar(Check, T...) -> void;
Deshalb ruft:
bar<void>(7, "");
nicht eindeutig ist.
Basierend auf dem oben genannten glaube ich, dass dies ein GCC-Bug ist.
Der Kern dieses Problems ist natürlich, dass beide Überladungen eine genaue Übereinstimmung zwischen den Argumenttypen und den formalen Parametern haben, so dass eine weitere Regel einsetzt, in welcher Überladung durch Vorlagenargumente. – MSalters
Gutfeeling sagt, dass es nicht zweideutig ist. Der zusätzliche Parameter sollte keinen Unterschied machen, da "ein Vorlagenparameter für die teilweise Bestellung ohne einen Wert bleiben kann, vorausgesetzt, er wird nicht in den Typen verwendet, die für die teilweise Bestellung verwendet werden." Es gibt ein Beispiel für diese Regel, die Ihrem Code entspricht modulo das Parameterpaket. –
Wenn Ihr zusätzliches Beispiel mit nur der 7 von gcc akzeptiert wird, erklärt mein Zitat nicht mehr diesen Verhaltensunterschied. –