Wpisz imię
„ typename
” to słowo kluczowe w języku programowania C++ używane podczas pisania szablonów . Służy do określania, że nazwa zależna w definicji szablonu lub deklaracji jest typem. W oryginalnych kompilatorach C++ przed ukończeniem pierwszego standardu ISO typename
nie było częścią języka C++, a Bjarne Stroustrup zamiast tego używał słowa kluczowego class
jako argumentów szablonu. Chociaż typename
jest teraz preferowanym słowem kluczowym, starszy kod źródłowy może nadal używać class
(na przykład zobacz różnice w przykładach kodu źródłowego między The Design and Evolution of C++ autorstwa Bjarne Stroustrup opublikowanym w 1994 r. a przykładami kodu źródłowego w The C++ Programming Language: Fourth Edition autorstwa Bjarne Stroustrup opublikowanym w 2013 r.).
Synonim słowa „ klasa
” w parametrach szablonu
ogólnej funkcji programowania C++, znanej jako „ szablony ”, nazwa typu może być użyta do wprowadzenia
parametru szablonu :
// Zdefiniuj funkcję ogólną, która zwraca większy ze swoich dwóch argumentów template < nazwa typu T > const T & max ( const T & x , const T & y ) { if ( y < x ) return x ; zwróć y ; }
Alternatywnym i semantycznie równoważnym słowem kluczowym w tym scenariuszu jest „ class
”:
// Zdefiniuj funkcję ogólną, która zwraca większy ze swoich dwóch argumentów template < class T > const T & max ( const T & x , const T & y ) { if ( y < x ) return x ; zwróć y ; }
Metoda wskazująca, że nazwa zależna jest typem
Rozważ ten nieprawidłowy kod:
template < nazwa typu T > void foo ( const T & t ) { // deklaruje wskaźnik do obiektu typu T::bar T :: bar * p ; // błąd (patrz tekst) } struct StructWithBarAsType { typedef int bar ; }; int main () { StructWithBarAsType x ; fuj ( x
); }
Ten kod wygląda tak, jakby powinien się skompilować, ale jest niepoprawny, ponieważ kompilator nie wie, czy T::bar
jest typem, czy wartością. Powodem, dla którego nie wie, jest to, że T::bar
jest „nazwą zależną od parametru szablonu” lub w skrócie „nazwą zależną”, która może wtedy reprezentować cokolwiek o nazwie „bar” wewnątrz typu przekazanego do foo(), co może zawierać typedefs , enums , zmienne itp.
Aby rozwiązać tę niejednoznaczność, standard języka C++ deklaruje:
Zakłada się, że nazwa używana w deklaracji szablonu lub definicji, która jest zależna od parametru szablonu, nie jest nazwą typu, chyba że odpowiednie wyszukiwanie nazw znajdzie nazwę typu lub nazwa jest kwalifikowana przez słowo kluczowe
typename
.
Krótko mówiąc, jeśli kompilator nie może stwierdzić, czy nazwa zależna jest wartością, czy typem, przyjmie, że jest to wartość.
W naszym przykładzie, gdzie T::bar
jest nazwą zależną, oznacza to, że zamiast deklarować wskaźnik do T::bar
o nazwie p
, wiersz
T::pasek * p;
zamiast tego pomnoży „wartość” T::bar
przez p
(której nigdzie nie można znaleźć) i odrzuci wynik. Fakt, że w StructWithBarAsType
zależny pasek
jest w rzeczywistości typem, nie pomaga, ponieważ foo()
można skompilować na długo przed zobaczeniem StructWithBarAsType .
Ponadto, jeśli istnieje również klasa taka jak:
struct StructWithBarAsValue { int bar ; };
wtedy kompilator byłby zobowiązany zinterpretować T::bar
w foo()
jako dostęp do elementu danych StructWithBarAsValue::bar
po utworzeniu instancji. Ale ponieważ bar
nie jest statycznym elementem danych, oznacza błąd.
Rozwiązaniem tego problemu jest jawne poinformowanie kompilatora, że T::bar
jest w rzeczywistości typem. W tym celu używane jest słowo kluczowe typename :
template < nazwa typu T > void foo ( const T & t ) { // deklaruje wskaźnik do obiektu typu T::bar nazwa typu T :: bar * p ; }
Teraz kompilator wie na pewno, że T::bar
jest typem i poprawnie uczyni p
wskaźnikiem do obiektu tego typu.
Zobacz też
- Wyszukiwanie nazw zależne od argumentów – kolejna reguła wyszukiwania nazw C++