2014-06-19 9 views
17

Der folgende Code wird von VC++ 2013 akzeptiert, aber von clang 3.4 abgelehnt.Ist es erforderlich, das Template-Argument einer Basisklasse anzugeben, wenn die Basisklasse ein Parametertyp einer Memberfunktion ist?

Welcher Compiler stimmt nach dem C++ - Standard?

template<class T> 
struct A 
{ 
    T n; 
}; 

template<class T> 
struct B : A<T> 
{ 
    // VC++ 2013 : OK 
    // clang : error : use of class template 'A' requires template arguments 
    B& f1(const A& obj) 
    { 
     return *this; 
    } 

    // VC++ : OK 
    // clang : OK 
    B& f2(const A<T>& obj) 
    { 
     return *this; 
    } 
}; 

int main() 
{ 
    B<int> b; 
} 
+2

Beachten Sie, dass g ++ auch einen Fehler ausgibt (http://coliru.stacked-crooked.com/a/38c78abd3f098143). – Jarod42

+0

Sieht aus wie ein erstklassiger Kandidat für das [tag: Sprache-Anwalt] -Tag, aber du bist schon bei 5 ... – Angew

Antwort

14

Mein erster Instinkt ist zu sagen, VC++ ist richtig in diesem. Lookup des Namens A in B sollte die injiziert-class-nameA innerhalb A<T> finden, die auch als Typname verwendet werden kann-A<T> zu verweisen.

C++ 11 [temp.local]:

1 Wie normale (Nicht-Template) Klassen, Klasse Vorlagen haben eine injizierte-class-name (Ziffer 9). Der eingegebene Klassenname kann als Vorlagenname oder als Typname verwendet werden. Wenn es mit einer Template-Argument-Liste, als Template-Argument für einen Vorlage Template-Parameter, oder als letzte Kennung in den erarbeitet-Typ-Spezifizierer einen Freund Klasse verwendet wird Template-Deklaration bezieht sich auf die Klassenvorlage selbst. Ansonsten entspricht es dem Schablonenname, gefolgt von den Vorlage-Parameter der Klassenvorlage in <>.

2 ...

3 Der injizierte-Klasse-Name einer Klasse oder Klassenschablone Template-Spezialisierung verwendet entweder als Template-Name oder Typname wo immer es in sein kann, ist, Umfang. [Beispiel:

template <class T> struct Base { 
    Base* p; 
}; 

template <class T> struct Derived: public Base<T> { 
    typename Derived::Base* p; // meaning Derived::Base<T> 
}; 

, jedoch zur gleichen Zeit, [temp.dep] §3 Zustände:

3 Bei der Definition einer Klasse oder Klassenschablone, wenn eine Basis Die Klasse hängt von einem Template-Parameter, der Basisklasse Bereich wird nicht während der nicht qualifizierten Namenssuche entweder bei der Definition der Klassenvorlage oder Mitglied oder während einer Instanziierung der Klassenvorlage oder Mitglied untersucht.

auf dieser Basis würde ich eher geneigt, dass Klappern zu sagen, tatsächlich richtig ist, da das injizierte-class-name A innerhalb des Umfangs von A<T> ist, die T auf B ‚s Template-Parameter abhängig und ist somit nicht gesucht während der Suche nach unqualifizierten Namen. Ein sekundärer Beweis dafür wäre die Tatsache, dass das Beispiel von [temp.local] Derived::Base statt nur Base verwendet.

Also insgesamt würde ich sagen, dass

  1. es ist eine schöne Ecke Fall und

  2. Klirren ist eigentlich Recht nicht den Umfang der A<T>

+1

14.6.1/3 (in n3337, wenn es relevant ist) – jrok

+0

@jrok Danke, sah es an . Allerdings musste ich meine Schlussfolgerung basierend auf 14.6.2/3 neu formulieren – Angew

5
zu untersuchen

Clang ist korrekt; Obwohl das injizierte -class-name der Klassenschablone A sicher sichtbar innerhalb A<T> und so sichtbar innerhalb der abgeleiteten Klasse ist B<T> ist es ein abhängigen Namen und so der Umfang Basisklasse innerhalb B<T> nicht untersucht.

Dependent Name Basisklasse Umfang Lookup wird in 14.6.2p3 diskutiert:

In der Definition einer Klasse oder Klassenvorlage, wenn eine Basisklasse auf einemTemplate-Parameter hängt, Umfang der Basisklasse wird nicht während der Suche nach nicht qualifizierten Namen entweder zum Zeitpunkt der Definition der Klassenvorlage oder des Members oder während einer Instanziierung der Klassenvorlage oder des Members untersucht.

Verwandte Themen