13

Ich schreibe etwas TMP-schweren Code für g ++ (Version 4.8.1_1, Macports) und clang ++ (Version 3.3, Macports). Während g ++ die folgende Code-Liste mit UNBRIDLED FURY ablehnt, kompiliert clang ++ mit grace und pracht.g ++ Fehler mit partieller Template-Spezialisierung

  • Welcher Compiler ist in der rechten? (Ich vermute stark, dass es g ++ ist, aber ich möchte vor dem Einreichen eines Fehlerberichts von anderen Rückversicherung erhalten.)
  • Haben Sie irgendwelche einfachen oder eleganten Problemumgehungen? (Ich brauche Vorlage Aliase zu verwenden, so Umschalten auf structs, die g verursacht ++, den Code zu akzeptieren, ist keine Option.)

Hier ist die Codeliste gemacht nur für Sie.

template <class... Ts> 
struct sequence; 

template <int T> 
struct integer; 

// This definition of `extents` causes g++ to issue a compile-time error. 
template <int... Ts> 
using extents = sequence<integer<Ts>...>; 

// However, this definition works without any problems. 
// template <int... Ts> 
// struct extents; 

template <int A, int B, class Current> 
struct foo; 

template <int A, int B, int... Ts> 
struct foo<A, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

template <int B, int... Ts> 
struct foo<B, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

int main() 
{ 
    using t = foo<1, 1, extents<>>::type; 
    return 0; 
} 

ist hier g ++ 's Ausgang:

er.cpp: In function 'int main()': 
er.cpp:39:41: error: ambiguous class template instantiation for 'struct foo<1, 1, sequence<> >' 
    using t = typename foo<1, 1, extents<>>::type; 
             ^
er.cpp:26:8: error: candidates are: struct foo<A, B, sequence<integer<Ts>...> > 
struct foo<A, B, extents<Ts...>> 
     ^
er.cpp:32:8: error:     struct foo<B, B, sequence<integer<Ts>...> > 
struct foo<B, B, extents<Ts...>> 
     ^
er.cpp:39:43: error: 'type' in 'struct foo<1, 1, sequence<> >' does not name a type 
    using t = typename foo<1, 1, extents<>>::type; 
             ^

Hier ist Klirren ++' s Ausgabe:

Vielen Dank für Ihre Hilfe!

+4

'+ 1' für Witze allein :) Ich würde auch wetten, dass Clang hier ist. –

+0

Der 'typenname' in' main' wird nicht benötigt –

+0

@ DavidRodríguez-dribeas Danke, es ist zur Gewohnheit geworden ... –

Antwort

7

Das scheint wie ein g ++ Bug weil foo<B, B, extents> ist spezialisierter als foo<A, B, extents> (te Letzteres kann alles übereinstimmen, dass das ehemalige übereinstimmt, aber nicht umgekehrt), so dass der Compiler diese Spezialisierung wählen sollte.

Wie Sie selbst festgestellt haben, löst die Änderung von extents von einem Vorlagenalias in eine Klassenvorlage das Problem.

3

Die Frage läuft darauf hinaus, wenn ich es richtig verstanden zu bestimmen, ob eine der folgenden Vorlage Spezialisierungen als die andere mehr spezialisiert ist:

template <int A, int B, class Current> 
struct foo; 

template <int A, int B, int... Ts> 
struct foo<A, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

template <int B, int... Ts> 
struct foo<B, B, extents<Ts...>> 
{ 
    using type = int; 
}; 

Und die Antwort ist ja, für eine beliebige Kombination von Parametern, In der zweiten Spezialisierung ist die gleiche Kombination erlaubt, wenn die Template-Argumente A == B sind. Auf der anderen Seite kann jede Instanziierung der ersten Template-Spezialisierung, bei der A != B keine Übereinstimmung für die zweite Spezialisierung sein kann, also die zweite spezialisierter als die erste sein.

0

Ich glaube, dass g ++ korrekt sein könnte. Die Linie

using t = foo<1, 1, extents<>>::type 

wird unter Verwendung der Template-Parameter in einem nicht abgeleiteten Kontext, so dass es nicht die tatsächlichen Werte gegeben für die Template-Parameter, die Mehrdeutigkeit beheben kann, nur ihre Art, und das ist nicht ausreichend.

Abschnitt 14.8.2.5 Abs 4 des Standard-C++ sagt:

In den meisten Fällen sind die Typen, Vorlagen und Nicht-Typ-Werte, die P mit bei Vorlage Argument Abzug verwendet werden, um zu komponieren. Das heißt, sie können verwendet werden, um den Wert eines Schablonenarguments zu bestimmen, und der so bestimmte Wert muss mit den anderweitig ermittelten Werten übereinstimmen.In bestimmten Kontexten nimmt der Wert jedoch nicht an der Typableitung teil, sondern verwendet stattdessen die Werte von Vorlagenargumenten, die entweder an anderer Stelle abgeleitet oder explizit angegeben wurden. Wenn ein Vorlagenparameter nur in nicht abgeleiteten Kontexten verwendet wird und nicht explizit angegeben wird, schlägt die Vorlagenargumentableitung fehl.

Die nicht abgeleitet Kontexte sind:

x Die verschachtelte-name-Bezeichner eines Typs, der eine qualifizierte Nummer mit

...

Abschnitt 14.8.2.4 angegeben wurde para 11 sagt:

in den meisten Fällen werden alle Template-Parameter-Werte, um für den Abzug ein tem erfolgreich zu sein, aber für partielle Ordnung Zwecke haben muss Der Plattenparameter darf ohne Wert bleiben, vorausgesetzt, er wird nicht in den Typen verwendet, die für die partielle Sortierung verwendet werden. [Hinweis: Ein Vorlagenparameter, der in einem nicht abgeleiteten Kontext verwendet wird, wird als verwendet betrachtet. -end note]

Wir befinden uns also in einem nicht-abgeleiteten Kontext, was bedeutet, dass alle Vorlagenargumente Werte haben müssen. Also, wenn Extents <> den Typ nicht festnageln, dann wird das Ergebnis gemäß dem Standard mehrdeutig sein. Plausibel?

+0

Die "P" -Ausdrücke sind 'A',' B', 'extents '. Die "A" Ausdrücke sind '1',' 1', 'Extents <>'. Kein "P" -Ausdruck verwendet einen Vorlagenparameter in einem nicht-abgeleiteten Kontext. – aschepler

+0

Stimmt der :: Typ am Ende nicht mit einer qualifizierten ID überein? –

+0

Ja, 'foo <1, 1, Extents <>> :: type' ist eine qualifizierte ID. Es verwendet jedoch keine Vorlagenparameter. Es enthält einige Template-Argumente ("A" in 14.8.2). Die Argumente in der qualifizierten ID werden mit denen für den Abzug verglichen; sie werden nicht abgeleitet. – aschepler