2015-06-24 7 views
7

Biorąc pod uwagę te definicjeKiedy możesz wyspecjalizować szablon dla prywatnego typu członka?

template<class T> class foo {}; 
template<class T> class foo1 { static int i; }; 
class bar { class baz {}; }; 

Jestem zaskoczony, że ten kompiluje

template<> 
class foo<bar::baz> {}; 

ale to się nie powiedzie się z powodu błędu 'class bar::baz' is private

template<> 
int foo1<bar::baz>::i = 42; 

Kiedy to się dzieje, i jest tam obejście inne niż uczynienie tego typu publicznym?

+0

To * jest * interesujące. Rozumiem, że to błąd definiujący zmienną tej klasy. Tj. 'Foo {};' jest OK (g ++), ale wtedy 'foo f;' nie jest. Tak więc jest to typ bezużyteczny i wygląda na to, że błąd pojawia się stosunkowo późno (tj. Nie w definicji klasy). –

+0

@AmiTavory Nie nadaje się do użytku, ponieważ zawsze możesz dodać [publiczny typ aliasu] (http://coliru.stacked-crooked.com/a/22807544d8414c4e). Ale ciekawe pytanie. Dlaczego istnieje kontrola dostępu do specjalizacji dla ':: i'? –

+0

@DanielFrey Rozumiem, że pytanie dotyczy przypadku bez modyfikowania kodu 'bar'. –

Odpowiedz

5

Rozważmy CWG #182:

Pewne kontroli dostępu są tłumione na wyraźnych dawałaby. 14.7.2 [temp.explicit] paragraf 8 mówi [...] Byłem zaskoczony, że podobne sformułowanie nie istnieje (które mogłem znaleźć) dla wyraźnych specjalizacji . Uważam, że te dwa przypadki powinny być traktowane równoważnie w poniższym przykładzie (tzn. Że dozwolona jest specjalizacja ).

template <class T> struct C { 
    void f(); 
    void g(); 
}; 

template <class T> void C<T>::f(){} 
template <class T> void C<T>::g(){} 

class A { 
    class B {}; 
    void f(); 
}; 

template void C<A::B>::f(); // okay 
template <> void C<A::B>::g(); // error - A::B inaccessible 

[...]

Przesłanki (październik 2002):

Mamy rozważyć to i zdecydował, że różnica między tymi dwoma przypadkach (Explicit specjalizacji i wyraźnej instancji) jest stosowne . Reguły dostępu są czasami zginane w razie potrzeby, aby zezwolić na nazywanie czegoś, tak jak w jawnej instancji, ale specjalna specjalizacja wymaga nie tylko nazwania encji, ale także dostarczenia gdzieś definicji.

GCC i Clang rzeczywiście nie odrzucać ostatnią linię pokazanym przykładzie, który - podobno - niespójne zachowanie, jak dla odpowiadającego wyraźnej specjalizacji szablonu klasy, nie wydać komunikat o błędzie:

template <class> struct T { 
    void g(); 
}; 

class A { class B; class C; }; 

template <> struct T<A::B>; // Ok 
template <> void T<A::C>::g(); // Error 

Demo. Więc pójdę w opałach tutaj i nazywają obu przypadkach wykazało źle uformowane przez §14.3/3:

nazwa Template-argumentu powinny być dostępne w punkcie gdzie to jest używany jako szablon-argument .

Powiązane problemy