2009-08-08 10 views
10

czytałem artykuł na SFINAE i napotkał następujący przykładowy kod:Dlaczego czasami trzeba wpisać `typename T` zamiast tylko` T`?

struct Test 
{ 
    typedef int Type; 
}; 

template < typename T > 
void f(typename T::Type) {} // definition #1 

template < typename T > 
void f(T) {}    // definition #2 

void foo() 
{ 
    f<Test> (10); //call #1 

    f<int> (10); //call #2 without error thanks to SFINAE 
} 

Teraz mam faktycznie napisany kod jak to wcześniej, i jakoś intuicyjnie wiedziałem, że muszę wpisać „typename T” zamiast tylko t". Jednak miło byłoby poznać faktyczną logikę, jaka za tym stoi. Czy ktoś chce wyjaśnić?

+1

Polecam przeczytać szablon faq: http://womble.decadentplace.org.uk/c++/template-faq.html –

Odpowiedz

8

Ogólnie składni C++ 's (odziedziczone C) ma defekt techniczny: parser musi wiedzieć, czy nazwy coś typu, czy nie, w przeciwnym razie po prostu nie może rozwiązać pewne niejasności (np jest X * Y mnożenie lub deklaracja wskaźnika Y do obiektów typu X? wszystko zależy od tego, czy X nazywa typ ...! -). typename "przymiotnik" pozwala ci to jasno i wyraźnie określić w razie potrzeby (co, jak wspomina inna odpowiedź, jest typowe, gdy chodzi o parametry szablonu ;-).

+1

Masz na myśli "zazwyczaj, gdy są zaangażowane parametry szablonu" (w takim przypadku jestem prawie pewien, że jest to * tylko *, gdy są zaangażowane parametry szablonu), lub jest to literówka dla "co jest typowe, gdy parametry szablonu są zaangażowane" ? –

+1

@onebyone, dobry połów, rzeczywiście miałem na myśli "typowy", a nie "typowo", zredagowałem moją odpowiedź na poprawkę, tx. –

13

Krótka wersja, którą należy wykonać typename X::Y, gdy X jest lub zależy od parametru szablonu. Dopóki X nie jest znany, kompilator nie może stwierdzić, czy Y jest typem czy wartością. Musisz więc dodać typename, aby określić, że jest to typ.

Na przykład:

template <typename T> 
struct Foo { 
    typename T::some_type x; // T is a template parameter. `some_type` may or may not exist depending on what type T is. 
}; 

template <typename T> 
struct Foo { 
    typename some_template<T>::some_type x; // `some_template` may or may not have a `some_type` member, depending on which specialization is used when it is instantiated for type `T` 
}; 

Jak SBI zwraca uwagę w komentarzach, przyczyną dwuznaczności jest Y może być statyczny element, enum lub funkcją. Nie znamy typu X, nie możemy powiedzieć. Standard określa, że ​​kompilator powinien przyjąć, że jest to wartość, chyba że została wyraźnie oznaczona jako typ za pomocą słowa kluczowego typename.

I to brzmi jak komentujących naprawdę chcesz mi wspomnieć o innej związanej sprawę także:;)

Jeśli nazwa zależna jest szablonem członek funkcja, i nazywają to z wyraźną szablonu argumentu (foo.bar<int>(), dla przykład), należy dodać słowo kluczowe template przed nazwą funkcji, jak w foo.template bar<int>().

Powodem jest to, że bez słowa kluczowego szablon, kompilator zakłada, że ​​bar jest wartością i chcesz wywołać na nim mniej niż operator (operator<).

+0

jalf, warto wspomnieć o alternatywnym znaczeniu 'T :: coś' (dane statyczne, nazwa funkcji). A kiedy już tak dobrze to zrobisz, warto dodać wyjaśnienie, dlaczego czasami musimy też wstrzykiwać "szablon". Ma to ten sam powód, więc nie potrwa to długo. – sbi

+0

"szablon" to jednak nie to samo rozumowanie. Nie ma nic wspólnego z nazwami zależnymi. Należy do kategorii "problemów, które mają tendencję do potknięcia się o szablony", ale nie sądzę, że jest to ten sam powód, co w przypadku "typename". – jalf

+1

@jalf: Czy nie ma to związku z nazwami szablonów? W każdym razie powody są dość analogiczne. Jest dozwolony tylko w kodzie szablonu i musi zostać użyty do odróżnienia nazw członków zależnych, które są nazwami szablonów od nazw członków zależnych, które nie są. –

3

Zasadniczo potrzebujesz słowa kluczowego typename podczas pisania kodu szablonu (np. Jesteś w szablonie funkcji lub szablonie klasy) i odnosisz się do indentyfikatora, który zależy od parametru szablonu, który może nie być znany jako typ, ale musi być zinterpretowany jako typ w kodzie szablonu.

W twoim przykładzie używasz typename T::Type z definicją # 1, ponieważ T::Type zależy od parametru szablonu i może być elementem danych.

Nie potrzebujesz typename T w definicji # 2 jako T jest zadeklarowany jako typ jako część definicji szablonu.

Powiązane problemy