2016-09-02 8 views
9

Alle Compiler kann ich meine Hände bekommt einig, dass dies in Ordnung:gcc vs. clang, msvc und icc: Ist dieser Funktionsaufruf mehrdeutig?

template <typename Check, typename... T> 
auto foo(Check, T...) -> void; 

template <typename... T> 
auto foo(int, T...) -> void; 

int main() 
{ 
    foo(7, ""); 
} 

jedoch der folgende Code (mit einem führenden Template-Parametern, die von dem Funktions nicht abgeleiteten Parametern werden können) nach gcc nicht eindeutig ist:

template <typename X, typename Check, typename... T> 
auto bar(Check, T...) -> void; 

template <typename X, typename... T> 
auto bar(int, T...) -> void; 

int main() 
{ 
    bar<void>(7, ""); // ambiguous according to gcc 
    bar<void>(7);  // just fine 
} 

Auf der anderen Seite sind clang, msvc und icc sehr zufrieden damit.

Welcher Compiler ist richtig?

Verweise auf die jeweiligen Abschnitte des Standards bevorzugt.

+0

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

+0

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. –

+0

Wenn Ihr zusätzliches Beispiel mit nur der 7 von gcc akzeptiert wird, erklärt mein Zitat nicht mehr diesen Verhaltensunterschied. –

Antwort

4

Dies ist core issue 200.

Die Beschreibung, wie die partielle Ordnung von Template-Funktionen ist [temp.func.order] Absätze in 14.5.6.2 bestimmt 3-5 nicht eine Bestimmung für nondeduced Template-Parameter macht. Zum Beispiel ist der Funktionsaufruf in dem folgenden Code nicht eindeutig, auch wenn man Vorlage „offensichtlich“ ist spezialisierter als die andere:

template <class T> T f(int); 
template <class T, class U> T f(U); 
void g() { 
    f<int>(1); 
} 

Der Grund dafür ist, dass weder Funktion Parameterliste ermöglicht T Template-Parameter zu sein abgeleitet; beide Ableitungen schlagen fehl, so dass weder die Vorlage als spezialisierter angesehen wird als die andere, und der Funktionsaufruf mehrdeutig ist.

Die Auflösung von core issue 214, die dies zu, [temp.deduct.partial]/11 reduziert wurden eingeführt: aber für partielle Ordnung Zwecke

In den meisten Fällen werden alle Template-Parameter-Werte, um für den Abzug haben muss, um erfolgreich zu sein Ein Vorlagenparameter darf ohne Wert bleiben, vorausgesetzt, er wird nicht in den Typen verwendet, die für die Teilbestellung verwendet werden.

Offenbar GCC die Umsetzung dieser Formulierung ist fehlerhaft, wenn Packs ins Spiel kommen.

0

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.

+0

Nachdem ich 14.5.6.2 [temp.func.order] jetzt mehrmals gelesen habe, kann ich immer noch nicht den Teil erkennen, der 'template auto bar (int, T ...) - > void; 'ist spezialisierter als' template automatischer Balken (Check, T ...) -> void; '. Kannst du mich auf die richtigen Sätze hinweisen? – Rumburak

Verwandte Themen