2017-11-12 1 views
2

Ich versuche, Bedeutung und Auswirkungen von 14.5.5/8 of the C++11 standard (idem in C++14 und ich nehme an, in C++ 17) zu versteheng ++ und Klirren ++ unterschiedliche Verhalten mit nicht-Typ Argumente in struct/class Spezialisierung

Der Typ eines Template-Parameters, der einem spezialisierten Nicht-Typ-Argument entspricht, darf nicht von einem Parameter der Spezialisierung abhängig sein.

und wie üblich zu verstehen, wer zwischen g ++ und clang ++ korrekt ist.

Der Standard anzeigen das folgende Beispiel

template <class T, T t> struct C {}; 
template <class T> struct C<T, 1>; // error 

und beide g ++ ++ und Klappern give Fehler.

So weit, so gut.

Lassen Sie uns ein wenig erschweren das Beispiel eine Art Zugabe

template <typename, typename T, T> 
struct foo { }; 

template <typename T> 
struct foo<T, int, 1> { }; // compile 

template <typename T> 
struct foo<T, T, 1> { }; // error 

Sowohl g ++ und Klirren ++ die erste Teil-Spezialisierung kompilieren (die Art der 1, int, ist kein Parameter der Spezialisierung) und geben Fehler mit der zweite (der Typ 1 ist T, ein Parameter der Spezialisierung)

So weit, so gut.

Lassen Sie uns eine Vorlage struct bar mit einem internen Typ vorstellen, dass hängt nicht von der Template-Parameter

template <typename> 
struct bar 
{ using type = int; }; 

und dem folgenden Programm

template <typename> 
struct bar { using type = int; }; 

template <typename, typename T, T> 
struct foo { }; 

template <typename T> 
struct foo<T, typename bar<T>::type, 1> { }; 

int main() 
{ } 

es ohne Fehler durch g kompiliert ++ (versucht in Wandbox mit 4.9.3, 5.5.0, 7.2.0 und Kopf 8.0.0, mit C++ 11, C++ 14 und, wenn verfügbar, C++ 17) aber Clang ++ (3.9.1, 4.0. 1, 5.0.0, Kopf 6.0.0; C++ 11, C++ 14, C++ 17) geben das folgende an Fehler

prog.cc:11:38: error: non-type template argument specializes a template parameter with dependent type 'T' 
struct foo<T, typename bar<T>::type, 1> { }; 
            ^
prog.cc:7:34: note: template parameter is declared here 
template <typename, typename T, T> 
           ~^ 

Wie immer: Wer hat Recht?

Klirren ++, die 1 abhängig von T betrachten (wenn typename bar<T>::type als int fest) oder g ++, dass diese Abhängigkeiten nicht entbindet?

Der Vollständigkeit halber muss ich sagen, dass bar Wechsel als

auf T, nichts ändern
template <typename T> 
struct bar { using type = T; }; 

so macht die bar<T>::type abhängig folgt: g ++ kompiliert ohne Fehler und Klirren ++ den gleichen Fehler geben.

Antwort

2

Betrachten Sie es aus der Sicht des Compilers.

template <class T, T t> struct C {}; 
template <class T> struct C<T, 1>; // error 

Für die Spezialisierung der Compiler nicht weiß, ob T tatsächlich einen Wert von 1 haben kann, und so ist die Spezialisierung ungültig.

Für

template <typename T> 
struct foo<T, typename bar<T>::type, 1> { }; 

Wer sagt, dass type ist immer int? Man könnte denken, dass es offensichtlich ist, aber ich konnte eine Spezialisierung von bar für einen bestimmten T so vorstellen, dass type ein std::string ist:

template<> 
struct bar<const volatile int> { using type = std::string }; 

Grundsätzlich Ihre Aussage „wenn typename bar<T>::type als int fixiert ist“ ist falsch Es ist nicht behoben.

Was nun? Der Standard sagt hier dasselbe wie für Ihr erstes Beispiel, die Spezialisierung ist schlecht geformt, weil, wie Ihr Zitat richtig angibt, der Typ des Nicht-Typparameters von einem anderen (Template-) Typ der Spezialisierung abhängt, nämlich T, der ist unbekannt. In dieser Hinsicht hat clang Recht, und gcc ist falsch.

Verwandte Themen