typnamn

" typnamn " är ett nyckelord i programmeringsspråket C++ som används när man skriver mallar . Det används för att ange att ett beroende namn i en malldefinition eller deklaration är en typ. I de ursprungliga C++-kompilatorerna innan den första ISO-standarden var klar nyckelordet typnamn inte en del av C++-språket och Bjarne Stroustrup använde istället klassnyckelordet för mallargument. Medan typnamn nu är det föredragna nyckelordet kan äldre källkod fortfarande använda klassnyckelordet istället (se till exempel skillnaden i källkodsexempel mellan The Design and Evolution of C++ av Bjarne Stroustrup publicerad 1994 och källkodsexemplen i The C++ Programming Språk: Fjärde upplagan av Bjarne Stroustrup publicerad 2013).

En synonym för " klass " i mallparametrar

I C++s generiska programmeringsfunktion känd som " mallar ", kan typnamn användas för att introducera en mallparameter :


  
       

     
     
   
 // Definiera en generisk funktion som returnerar det största av dess två argument  mall  <  typnamn  T  >  const  T  &  max  (  const  T  &  x  ,  const  T  &  y  )  {  if  (  y  <  x  )  return  x  ;  returnera  y  ;  } 

Ett alternativt och semantiskt likvärdigt nyckelord i detta scenario är " klass ":


  
       

     
     
   
 // Definiera en generisk funktion som returnerar det största av dess två argument  mall  <  class  T  >  const  T  &  max  (  const  T  &  x  ,  const  T  &  y  )  {  if  (  y  <  x  )  return  x  ;  returnera  y  ;  } 

En metod för att indikera att ett beroende namn är en typ

Tänk på den här ogiltiga koden:

  
   

   
       


 

     


 

    
   
 mall  <  typnamn  T  >  void  foo  (  const  T  &  t  )  {  // deklarerar en pekare till ett objekt av typen T::bar  T  ::  bar  *  p  ;  // error (se text)  }  struct  StructWithBarAsType  {  typedef  int  bar  ;  };  int  main  ()  {  StructWithBarAsType  x  ;  foo  (  x  );  } 

Den här koden ser ut som den borde kompilera, men den är felaktig eftersom kompilatorn inte vet om T::bar är en typ eller ett värde. Anledningen till att den inte vet är att T::bar är ett "mallparameterberoende namn", eller förkortat "beroende namn", som sedan kan representera allt som heter "bar" inuti en typ som skickas till foo(), vilket kan inkludera typedefs , enums , variabler etc.

För att lösa denna tvetydighet deklarerar C++ Language Standard :

Ett namn som används i en malldeklaration eller definition och som är beroende av en mallparameter antas inte namnge en typ om inte den tillämpliga namnsökningen hittar ett typnamn eller namnet kvalificeras av nyckelordet typnamn .

Kort sagt, om kompilatorn inte kan avgöra om ett beroende namn är ett värde eller en typ, kommer den att anta att det är ett värde.

I vårt exempel, där T::bar är det beroende namnet, betyder det att snarare än att deklarera en pekare till T::bar med namnet p , raden

T::bar * p;

kommer istället att multiplicera "värdet" T::bar med p (som ingenstans finns) och slänga resultatet. Det faktum att den beroende stapeln i StructWithBarAsType faktiskt är en typ hjälper inte eftersom foo() kunde kompileras långt innan StructWithBarAsType ses. Dessutom, om det också finns en klass som:

 

     
 struct  StructWithBarAsValue  {  int  bar  ;  }; 

då skulle kompilatorn vara skyldig att tolka T::baren i foo() som en åtkomst till datamedlemmen StructWithBarAsValue::bar när den instansierades. Men eftersom bar inte är en statisk datamedlem kommer den att flagga ett fel.

Lösningen på detta problem är att uttryckligen tala om för kompilatorn att T::bar faktiskt är en typ. För detta används nyckelordet typnamn :

  
   

   
      
 mall  <  typnamn  T  >  void  foo  (  const  T  &  t  )  {  // deklarerar en pekare till ett objekt av typen T::bar  typnamn  T  ::  bar  *  p  ;  } 

Nu vet kompilatorn med säkerhet att T::bar är en typ, och kommer korrekt att göra p till en pekare till ett objekt av den typen.

Se även