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ż