Differenza delle parole chiave "typename" e "class" nei template?


504

Per i modelli ho visto entrambe le dichiarazioni:

template < typename T >
template < class T >

Qual è la differenza?

E cosa significano esattamente quelle parole chiave nel seguente esempio (tratto dall'articolo di Wikipedia in tedesco sui modelli)?

template < template < typename, typename > class Container, typename Type >
class Example
{
     Container< Type, std::allocator < Type > > baz;
};

Risposte:


430

typenamee classsono intercambiabili nel caso di base per specificare un modello:

template<class T>
class Foo
{
};

e

template<typename T>
class Foo
{
};

sono equivalenti.

Detto questo, ci sono casi specifici in cui esiste una differenza tra typenameeclass .

Il primo è nel caso di tipi dipendenti. typenameviene utilizzato per dichiarare quando si fa riferimento a un tipo nidificato che dipende da un altro parametro del modello, come ad esempio typedefin questo esempio:

template<typename param_t>
class Foo
{
    typedef typename param_t::baz sub_t;
};

Il secondo che mostri effettivamente nella tua domanda, anche se potresti non rendertene conto:

template < template < typename, typename > class Container, typename Type >

Quando si specifica un modello di modello , la classparola chiave DEVE essere utilizzata come sopra - in questo caso non è intercambiabile (nota: poichétypename in questo caso C ++ 17 sono consentite entrambe le parole chiave) .

È inoltre necessario utilizzare classquando si crea un'istanza esplicita di un modello:

template class Foo<int>;

Sono sicuro che ci sono altri casi che mi sono perso, ma la linea di fondo è: queste due parole chiave non sono equivalenti e questi sono alcuni casi comuni in cui è necessario utilizzare l'uno o l'altro.


45
Quest'ultimo è praticamente un caso speciale del fatto che è necessario utilizzare class o struct, non typename, per definire una classe. Ovviamente nessuno dei tuoi primi due bit di codice può essere sostituito template <typename T> typename Foo {};, perché Foo <T> è sicuramente una classe.
Steve Jessop,

2
std::vector<int>::value_typenon è un tipo dipendente, non è necessario typenamelì - ne hai bisogno solo se un tipo dipende da un parametro modello, ad esempiotemplate<class T> struct C { typedef typename std::vector<T>::value_type type; };
Georg Fritzsche,

2
E ancora, param_tnon è un tipo dipendente. I tipi dipendenti sono nomi che dipendono da un parametro del modello , ad esempio foo<param_t>::some_type, non dai parametri del modello stessi.
Georg Fritzsche,

2
Una proposta C40 1z N4051 ti permetterà di usare typename, ad es template <typename> typename C.
user4112979,

4
A partire da oraGCC 5 , G ++ consente il nome tipografico in un parametro di modello di modello .
Chnossos,

95

Per la denominazione dei parametri del modello typenamee classsono equivalenti. §14.1.2:

Non esiste alcuna differenza semantica tra classe e typename in un parametro template.

typenametuttavia è possibile in un altro contesto quando si usano i template - per suggerire al compilatore che ci si riferisce a un tipo dipendente. §14.6.2:

Si presume che un nome utilizzato in una dichiarazione o definizione di modello che dipende da un parametro modello non assegni un tipo a meno che la ricerca del nome applicabile non trovi un nome di tipo o il nome non sia qualificato dalla parola chiave typename.

Esempio:

typename some_template<T>::some_type

Senza typenameil compilatore non si può dire in generale se ci si riferisce a un tipo o no.


2
Comprendo la regola, ma cosa impedisce esattamente al compilatore di trattare some_template <T> come un tipo internamente? Scusa se mi manca qualcosa di ovvio.
Batbrat,

23

Sebbene non vi sia alcuna differenza tecnica, ho visto i due usati per indicare cose leggermente diverse.

Per un modello che dovrebbe accettare qualsiasi tipo come T, inclusi gli incorporati (come un array)

template<typename T>
class Foo { ... }

Per un modello che funzionerà solo dove T è una vera classe.

template<class T>
class Foo { ... }

Ma tieni presente che questa è puramente una cosa di stile che alcune persone usano. Non richiesto dalla norma o applicato dai compilatori


15
Non ti biasimo per averlo menzionato, ma penso che questa politica sia piuttosto sbagliata, dal momento che i programmatori finiscono per prendersi il tempo a pensare a qualcosa che non ha importanza ("ho usato quello giusto?") Per indicare qualcosa che non ' non importa ("esiste un tipo incorporato che implementa l'interfaccia richiesta per questo parametro template?"). Se vengono utilizzati membri del parametro template ( T t; int i = t.toInt();), è necessaria una "classe reale" e il codice non verrà compilato se si fornisce intper T...
Steve Jessop,

1
Se vuoi limitare l'uso alle classi effettive, è meglio aggiungere una specializzazione per lanciare / causare un errore per i tipi non di classe. Se vuoi limitare l'uso a determinate classi, specializza solo per loro. In ogni caso, una tale distinzione stilistica è troppo sottile per far passare il messaggio.
Potatoswatter

2
Dal momento che intendevano la stessa cosa, per favore usane solo una. Altrimenti, è come usare inline {, a meno che non sia un martedì, e poi usi la riga successiva {.
Paul Draper,

+1 Lo faccio anch'io a volte ... classimplica che non ti stai solo aspettando un "valore", forse supportando alcuni operatori, copiando o spostando la costruzione e / o il compito, ma in particolare hai bisogno di un tipo che supporti alcune semantiche di accesso dei membri. La rapida occhiata alla dichiarazione fissa quindi aspettative e scoraggi, ad esempio fornendo tipi classpredefiniti per i parametri quando ciò sarebbe certamente un errore.
Tony Delroy,

Mi piacerebbe capire quali tipi di situazioni del mondo reale esistono in cui un modello funzionerebbe per QUALSIASI classe, ma non funzionerebbe con tipi incorporati. Hai un esempio?
lfalin,

7
  1. Nessuna differenza
  2. Il parametro del tipo di modello Containerè esso stesso un modello con due parametri di tipo.

3
c'è una differenza in generale.
Hassan Syed,

potrebbero anche essere nominati quei due parametri con cui è stato modellato il contenitore? nell'esempio non hanno alcun nome. E anche - in questo esempio è scritto "contenitore di classe" - potrebbe invece essere scritto anche "contenitore di nomi"?
Mat

2
@Mat: sì, il termine da cercare è parametri / argomenti del modello di modello . Ad esempio:template<template<class U> class V> struct C {};
Georg Fritzsche,

6

Questo frammento è tratto dal libro di primer c ++. Anche se sono sicuro che sia sbagliato.

Ogni parametro di tipo deve essere preceduto dalla classe di parole chiave o dal nome di battitura:

// error: must precede U with either typename or class
template <typename T, U> T calc(const T&, const U&);

Queste parole chiave hanno lo stesso significato e possono essere utilizzate in modo intercambiabile all'interno di un elenco di parametri del modello. Un elenco di parametri del modello può utilizzare entrambe le parole chiave:

// ok: no distinction between typename and class in a template parameter list
template <typename T, class U> calc (const T&, const U&);

Può sembrare più intuitivo utilizzare la parola chiave typename piuttosto che class per designare un parametro di tipo template. Dopotutto, possiamo usare i tipi predefiniti (non di classe) come argomento del tipo di modello. Inoltre, typename indica più chiaramente che il nome che segue è un nome di tipo. Tuttavia, typename è stato aggiunto a C ++ dopo che i template erano già ampiamente utilizzati; alcuni programmatori continuano a usare esclusivamente la classe

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.