Wie lautet die Syntax für die teilweise Spezialisierung einer Vorlage basierend auf der Anzahl der Parameter, die ein Vorlagenvorlagenparameter benötigt?

8

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

  • Der Code wird ordnungsgemäß in GCC kompiliert, wodurch angezeigt wird, dass OneParam und TwoParam sich von TTP in der primären Vorlage unterscheiden.
  • Clang erkennt nicht, dass 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.
  • MSVC gibt ähnliche Fehler wie Clang aus, jedoch prägnanter: Er gibt C3855 ( 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.

    
Justin Time 16.11.2016, 02:14
quelle

1 Antwort

1

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:

  1. Ein variadischer Template-Vorlagenparameter kann auf einen Template-Vorlagenparameter mit einem Argument und umgekehrt abgeleitet werden . gcc ist der einzige Compiler, der das richtig macht.
  2. Eine Vorlage mit einem Argument ist spezialisierter als eine variadische Vorlage . Alle modernen Compiler machen das richtig.
  3. Dementsprechend ist eine Funktionsvorlage, die einen Vorlagenvorlagenparameter mit einem Argument verwendet, spezialisierter als eine Funktion Vorlage, die einen variadischen Vorlagenschablonenparameter verwendet. Der einzige Compiler, der dies zu korrigieren scheint, ist ICC, aber nur weil er (1) falsch ist.
  4. Dementsprechend ist eine Klassenvorlage, die einen Vorlagenvorlagenparameter mit einem Argument verwendet, spezieller spezialisiert als eine Klasse Vorlage, die einen variadischen Vorlagenschablonenparameter verwendet. ICC und gcc scheinen das zu korrigieren, aber im ersten Fall, weil sie (1) falsch und gcc inkonsistent mit (3) erhalten.

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.

Vollständige Analyse

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:

%Vor%

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:

%Vor%

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:

%Vor%

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 .

    
ecatmur 20.06.2017 22:56
quelle