Betrachten Sie den folgenden Code:
%Vor% Dieser Code wird ordnungsgemäß in Clang, GCC und MSVC kompiliert, wenn TEST_TTP
nicht definiert ist. Wenn es jedoch ist definiert ist ...
OneParam
und TwoParam
sich von TTP
in der primären Vorlage unterscheiden. OneParam
specialists TTP
ist und verursacht zwei Fehler (der erste ist, dass die partielle Spezialisierung keine Template-Parameter spezialisiert, und der zweite ist, dass OneParam
mit dem vorherigen Konflikt in Konflikt steht -declared Vorlage Vorlage Parameter). Er gibt dann ähnliche Fehler für TwoParam
aus (der erste ist identisch, während der zweite sagt, dass der Template-Vorlagenparameter zu viele Parameter hat) und ein Fehler für jede Instanziierung von SS
(weil er die Vorlage als undefiniert ansieht) , für insgesamt 6 Fehler. OneParam
ist mit der primären Vorlage inkompatibel) und C2079 (Variable verwendet undefinierten Typ) für jede Instanziierung von SS
aus, insgesamt also 3 Fehler. Demonstriert live auf auf Coliru .
Aus meiner Prüfung:
GCC ermöglicht ein Template mit einem Template-Template-Parameter, bei dem ein variadisches Parameterpaket nur teilweise auf der Basis der Anzahl der Parameter, die der Template-Template-Parameter benötigt, partiell spezialisiert ist. Clang und MSVC nicht.
%Vor%Clang und MSVC sind in Ordnung, wenn auch andere Parameter spezialisiert sind.
%Vor%Es scheint also so zu sein, dass entweder ersteres nicht legales C ++ ist oder von Clang und MSVC nicht richtig unterstützt wird. Die Frage ist also:
In Anbetracht dessen, was ist die richtige, legale Syntax für die teilweise Spezialisierung einer Vorlage, die einen Template-Vorlagenparameter enthält, basierend auf der Anzahl der Parameter, die der Template-Vorlagenparameter benötigt? Wenn es keine legale Syntax dafür gibt, unterstützt es eine GCC-Erweiterung und / oder einen Fehler?
Wenn eine vollständige Aufzeichnung der von mir durchgeführten Tests zusammen mit dem ursprünglichen Beispiel, das diese Frage ausgelöst hat, erwünscht ist, sehen Sie sich bitte den Bearbeitungsverlauf an.
tl; dr: Ihr Code ist gültig, aber kein Compiler behandelt ihn richtig; Selbst diejenigen, die es akzeptieren (gcc und ICC (Intel C ++ Compiler)), tun dies inkonsistent oder aus dem falschen Grund.
Die richtige Argumentation lautet wie folgt:
Fazit: Sie verwenden die richtige, legale Syntax; Sie benötigen jedoch wahrscheinlich Workarounds für nicht kompatible Compiler. Selbst wenn der Code kompiliert wird, würde ich empfehlen, static_assert
zu verwenden, um zu überprüfen, ob die erwartete Funktionsüberladung oder die partielle Spezialisierung der Klassenvorlage ausgewählt wurde.
Per [temp.class.order] , wir teilweise Sortieren von Klassenschablonen-Teilspezialisierungen durch Umschreiben in überladene Funktionsvorlagen:
%Vor% Wie erwartet, lehnt clang diese Neuschreibung ab und behauptet, dass der Aufruf von f
ebenso zweideutig ist wie MSVC; gcc weist dieses Umschreiben inkonsistent zurück, obwohl es die ursprüngliche partielle Spezialisierung der Klassenvorlage akzeptiert hat. ICC akzeptiert diese Neuschreibung und initialisiert ssoi
zu 1
, entsprechend der OneParam
Spezialisierung #1
.
Jetzt können wir feststellen, welcher Compiler korrekt ist, indem Sie die Regeln für die partielle Sortierung von Funktionsvorlagen befolgen ( [temp.func.order] ). Wir können sehen, dass der Aufruf von f
bei der Initialisierung von ssoi
entweder #0
oder #1
aufrufen kann. Um festzustellen, welche spezialisierter ist, müssen wir Template-Argumente synthetisieren und versuchen, eine Typableitung durchzuführen:
Beachten Sie, dass pro [temp.func.order] / 5 keine Argumente synthetisiert werden, die Ts...
entsprechen.
Abzug in #1 -> #0
gelingt ( TTP := OneParam1; Ts... := {}
), wie erwartet ( #1
ist das Umschreiben entsprechend einer teilweisen Spezialisierung der Klassenschablone, wobei #0
das Umschreiben ist).
Abzug in #0 -> #1
gelingt ( OneParam := TTP0; Ts... := {}
) unter gcc und MSVC. clang (inkonsistent) und ICC ablehnen f1
, wobei angegeben wird, dass TTP0
nicht zu OneParam
abgeleitet werden kann (clang: "Kandidatenvorlage ignoriert: Substitutionsfehler: Vorlagenvorlagenargument hat andere Vorlagenparameter als der entsprechende Vorlagenparameter").
Also müssen wir zuerst feststellen, ob der Abzug #0 -> #1
tatsächlich durchführbar ist. Wir können einen einfacheren, äquivalenten Fall betrachten:
Dies wird von gcc akzeptiert und von MSVC (inkonsistent), clang und ICC zurückgewiesen. Gcc akzeptiert dies jedoch gemäß [temp.arg.template] / 3 .
Als nächstes müssen wir feststellen, ob #1
spezialisierter ist als #0
oder ob sie hinsichtlich der Reihenfolge mehrdeutig sind. Pro [temp.deduct.partial] / 10 betrachten wir die Typen in #0
und #1
nacheinander; pro [temp.arg.template] / 4 können wir OneParam
und TTP
gleichzeitig in Funktionsschablonen umschreiben:
Wir haben jetzt Teilauftrag die neu geschriebenen f
und g
Überladungen, die durch < strong> [temp.deduct.partial] und [temp.deduct.type] , um dies anhand der tie-brecher für variadics #1
ist spezialisierter als #0
.
Tags und Links c++ visual-c++ template-templates g++ clang++