2015-11-17 12 views
12

Betrachten Sie das folgende:Template alias Sichtbarkeit in verschachtelte Klasse

template<typename X> 
struct Z {}; 

struct A 
{ 
    using Z = ::Z<int>; 

    struct B : Z 
    { 
     using C = Z; 
    }; 
}; 

Dies kompiliert in Ordnung. Nett. Aber fügen Sie nun einen anderen Parameter in Z:

template<typename X, typename Y> 
struct Z {}; 

struct A 
{ 
    template<typename X> 
    using Z = ::Z<X, int>; 

    struct B : Z<B> 
    { 
     using C = Z<B>; // error: too few template arguments for class template 'Z' 
    }; 
}; 

Ok, vielleicht ist es sinnvoll, dass die Definition der Vorlage alias Z in Klasse A sichtbar ist, wenn verschachtelte Klasse abgeleitet B, aber nicht in seinem Körper, die Auslösung der Fehler, da die globale Definition von Z hat zwei Parameter.

Aber warum das Verhalten unterschiedlich im ersten Fall ist, wenn Z nur eine Art Alias ​​in A ist?

Schließlich machen A eine Vorlage:

template<typename X, typename Y> 
struct Z {}; 

template<typename T> 
struct A 
{ 
    template<typename X> 
    using Z = ::Z<X, int>; 

    struct B : Z<B> 
    { 
     using C = Z<B>; 
    }; 
}; 

Jetzt ist der Fehler verschwunden ist. Warum?

(getestet auf Clang 3.6 und GCC 4.9.2)

Antwort

9

Kurz gesagt: die sich aus einer Spezialisierung der Z führt die injizierten-class-name von ::Z, die vor der Alias-Vorlage gefunden wird. Wenn A eine Vorlage ist, wird jedoch der Name der eingefügten Klasse nicht mehr gefunden, da die Basisklasse von B abhängig ist. Betrachten


[temp.local]/1:

Wie normale (nicht-Template) Klassen, Klassen-Templates haben eine injiziert-class-name (Ziffer 9). Die injizierten -class-name kann als Template-Namen oder Typname verwendet werden.

Und [basic.lookup]/3:

Der injizierten -class-name eine Klasse (Ziffer 9) ist auch als ein Mitglied dieser Klasse für die Zwecke sein, von Name [...] Nachschlagen.

Z wird als ein unqualifizierter Name nachgeschlagen; [Basic.lookup.unqual]/7:

enter image description here

Somit ist der injizierte -class-nameZ wird als Mitglied der Basisklasse gefunden Z<B, int> und als Template-Name verwendet , die dein zweites Programm schlecht gemacht macht.In der Tat, die erste Schnipsel verwendet die injiziert-class-name als auch - das folgende Snippet wird nicht kompiliert:

struct A 
{ 
    using Z = ::Z<float>; 
    struct B : ::Z<int> 
    { 
     static_assert(std::is_same<Z, ::Z<float>>{}, ""); 
    }; 
}; 

Wenn schließlich A eine Vorlage gemacht wird, beachten Sie, dass B eine abhängige Art wie pro [temp.dep.type]/(9.3) , also Z<B> ist ein abhängiger Typ nach [temp.dep.type]/(9.7), daher wird die Basisklasse Z<B> während der Suche nach nicht untersucht unqualifizierte IDZ nach [temp.dep]/3:

In der Definition einer Klasse [..], der Umfang einer abhängige Basisklasse (14.6.2.1) wird nicht während der unqualifizierten Namenssuche entweder am Punkt der Definition der Klasse Vorlage oder Mitglieds untersucht, oder während einer Instanziierung der Klassenvorlage oder des Members.

Daher wird injected-class-name nicht gefunden.


B ist eine "nested Klasse [..], das ein Mitglied abhängigen des aktuellen Instanziierung ist" (Hervorhebung von mir), da

Ein Name ist ein abhängigen Mitglied der aktuellen Instanziierung, wenn es ein Mitglied der aktuellen Instanziierung ist, die, wenn nachgeschlagen, bezieht sich auf mindestens ein Mitglied einer Klasse, die die aktuelle Instanziierung ist.

+0

Wow. Das ist ziemlich klar, danke. Der Fehler tauchte tatsächlich auf, als "A" aufhörte, eine Vorlage zu sein, was, wie ich dachte, den Code sehr vereinfachen würde. Ich bin jedoch gezwungen, zwei verschiedene Namen für die zwei Z zu verwenden, was den Code nur hässlicher macht. Wenn es einen besseren Workaround gibt, lass es mich wissen. – iavr

+0

@iavr Was ist mit 'mit C = Z;'? (Wird nicht funktionieren, wenn 'A' eine Vorlage ist) – Columbo

+0

Nun, das ist beeindruckend :-) Ja, es funktioniert hier an diesem vereinfachten Code, aber nicht an meinem ursprünglichen (' unbekannter Typname 'Z''). Ich muss überprüfen, wo der Unterschied ist. 'A' ist keine Vorlage mehr, und ich beabsichtige, es so zu halten. – iavr