2014-10-25 15 views
5

Il seguente codice viene compilato con successo con clangore 3.5.0 e g ++ 4.9.0 (con -Wall -Wextra -pedantic-errors bandiere) sotto C++03 (flag -std=C++03), C++11 (flag -std=C++11) e C++14 (flag -std=C++14):Parola chiave extra typename nell'elenco dei parametri del modello: è valida o no?

namespace N 
{ 
    typedef int T; 

    enum E{}; 
} 

template <typename N::T> 
struct ST{}; 

template <typename N::E> 
struct SE{}; 

int main() 
{ 
} 

E 'valida per aggiungere ulteriore typename parola chiave prima di una dichiarazione di parametro modello non di tipo?


Si noti che il seguente codice non viene compilato (come C++03, C++11, e C++14 codice):

typedef int T; 

enum E{}; 

template <typename T t> 
struct ST{}; 

template <typename E e> 
struct SE{}; 

int main() 
{ 
} 

Ma il successivo compila bene ancora una volta (C++03, C++11, e C++14) :

typedef int T; 

enum E{}; 

template <typename ::T> 
struct ST{}; 

template <typename ::E> 
struct SE{}; 

int main() 
{ 
} 
+0

Sospetto che 'typename N :: T' venga analizzato come parametro di tipo, non correlato al tipo effettivo' N :: T'. Il nome di questo è strano, comunque. – leemes

+0

@dyp E cosa dovrebbe seguire dal tuo preventivo? – Constructor

+0

@leemes Sì, lo penso anch'io. Ed è * molto * strano. – Constructor

risposta

6

È consentito, ma solo con nomi qualificati:

typename-specifier:
                  typenameidentificatore nested-nome-identificatore
                    typenamenested-nome-identificatore template opt semplice-template-id

Quindi typename E è sbagliato secondo la grammatica. typename N::E non è da quando il nome è qualificato. Il terzo caso, typename ::E, va bene poiché :: è un identificatore nome nidificato valido.

I C++ 03 previsto dalla norma in [temp.res]/5 che

La parola chiave typename si applica solo ai nomi qualificati, ma quei nomi non devono essere dipendente.

I C++ 11 stati standard questo da nessuna parte in modo esplicito, ma all'interno di una nota in [temp.names]/5:

[Nota: Come è il caso con il prefisso typename, il template prefisso è consentito nei casi in cui non è strettamente necessario; cioè, quando il nested-nome-identificatore o l'espressione a sinistra del -> o . non è dipendente da una modello-parametro, o l'uso non appare nel campo di applicazione di un modello. - nota fine]

La stessa nota esiste nella stessa identica posizione nello standard C++ 14.

+0

Quindi, se il nome non dipende, 'typename' è superfluo? – 0x499602D2

+0

@ 0x499602D2 Sì. 'typename' è per la disambiguazione; se non c'è bisogno di disambiguazione, allora 'typename' non è richiesto;) – dyp

+0

@ 0x499602D2 Certamente. – Columbo

Problemi correlati