2015-01-19 22 views
11

Perché è che caso non corretto (è logico)typedef e il modello di parametro con lo stesso nome

template <typename T> 
struct Der: public Base 
{ 
    typedef int T; 
    T val; 
}; 

, ma questo caso è corretto?

struct Base 
{ 
    typedef int T; 
}; 

template <typename T> 
struct Der: public Base 
{ 
    T val; 
}; 

Lo Standard 14.6.1/7 dice:

Nella definizione di un modello di classe o nella definizione di un membro di tale modello che appare al di fuori della definizione del modello, per ogni classe base che non dipende da un parametro template (14.6.2), se il nome della classe base o il nome di un membro della classe base è uguale al nome di un parametro template, il nome della classe base o nome utente nasconde il nome del parametro template (3.3.7).

Perché non è ambiguo qui?

risposta

15

Il primo esempio è corretto secondo [temp.local]/6:

A modello-parametro non devono essere dichiarato nuovamente nel suo ambito (compresi scope nidificati).

Tuttavia, in

template <typename T> 
struct Der: public Base 
{ 
    T val; 
}; 

T è nascosto sotto il nome ereditato da Base - come specificato dal tuo preventivo.

[..] se il nome della classe di base o il nome di un membro della classe base è lo stesso che il nome di un modello di parametri, il nome della classe di base o il nome utente nasconde il parametro modello di modello nome (3.3.7).

Cioè, il membro val è di tipo int. Demo.

+0

Grazie per la risposta, ma quali sono le ragioni di tale comportamento? – user3514538

+1

@ user3514538 La ridichiarazione di un parametro del modello probabilmente causerebbe problemi con [basic.scope.class]/1 - un paragrafo importante. Per non parlare dell'ODR. Tuttavia, riguardo al secondo bit, non ne sono sicuro. Dovremmo aspettare per hvd: o) – Columbo

+1

Questo sembra essere soggetto a [CWG 591] (http://open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#591), anche se questo limita solo questo regola per classi base non dipendenti. – dyp

1

Perché il secondo è unambigous:

Potrebbe non cura o sapere che c'è stata la typedev int T nella superclasse, ma hai appena introdotto T come parametro di template, che rende chiaro che si sta facendo riferimento alla quando si utilizza T in Der.

+3

Il 'T' in derivato è in realtà il membro della base,' Base :: T', nel secondo esempio. Questo sembrerebbe contraddire la tua risposta - o mi sto perdendo qualcosa? –

+0

Non credo che questa risposta sia _wrong_ di per sé, ma in realtà non spiega nulla. –

+0

@LightnessRacesinOrbit 'T' si riferisce al typedef della classe base. La risposta dice * "hai appena introdotto' T' come parametro template, il che rende chiaro che ti stai riferendo ad esso quando usi 'T' in Der." * – Columbo

2

In generale, lo standard tenta di garantire che il significato di un tipo in un determinato ambito sia lo stesso.

Se si presuppone che il typedef è consentito, considerare i tipi di val1, val2 e val3 in seguito?

template <typename T> 
struct Der: public Base 
{ 
    void f1() { 
     T val1;  // What is the type of 'val1'? 
    } 

    T val2;  // What is the type of 'val2'? 

    typedef int T; 

    T val3;  // What is the type of 'val3'? 
}; 

L'unica variabile ad avere il tipo di parametro template T sarebbe 'val2'.

Questo perché lo standard richiede che tutti i membri della classe siano "nell'ambito" per f1. Questo è il motivo per cui le funzioni membro possono fare riferimento a variabili membro definite successivamente nel corpo della classe.

Lo stesso problema può essere illustrato con typedef troppo:

typedef int T; 

struct S 
{ 
    T x; 
    typedef float T; 
    T y; 
}; 

Ancora una volta, se questo era legale allora il T utilizzato per la dichiarazione di x si riferirebbe al ::T e la T utilizzato per y si riferirebbe a typedef S::T.

Questa è coperto dallo standard ISO 3.3.7/1:

le seguenti regole descrivono la portata dei nomi dichiarati nelle classi.

...

2) Un nome N utilizzato in una classe S si riferiscono alla stessa dichiarazione nel suo contesto e quando rivalutato nel campo di applicazione completa di S. Non è necessaria diagnostica per una violazione di questa regola.

Problemi correlati