Propagazione di "typedef" dalla base alla classe derivata per "template"
-
10-07-2019 - |
Domanda
Sto cercando di definire la classe base, che contiene solo typedef.
template<typename T>
class A
{
public:
typedef std::vector<T> Vec_t;
};
template<typename T>
class B : public A<T>
{
private:
Vec_t v; // fails - Vec_t is not recognized
};
Perché in B ricevo un errore che Vec_t non viene riconosciuto e devo scriverlo esplicitamente?
typename A<T>::Vec_t v;
Soluzione
Credo che questa domanda sia duplicata, ma non riesco a trovarla ora. Lo standard C ++ afferma che è necessario qualificare completamente il nome in base al 14.6.2 / 3:
Nella definizione di un modello di classe o di un membro di un modello di classe, se una classe di base del modello di classe dipende da un parametro modello, l'ambito della classe di base non viene esaminato durante la ricerca del nome non qualificato nel punto di definizione del modello di classe o del membro o durante un'istanza del modello di classe o del membro.
UPD: ho finalmente trovato un duplicato: eccolo .
Altri suggerimenti
Esiste qualcosa chiamato nomi dipendenti e non dipendenti in caso di modelli.
Se il nome dipende dal parametro T del modello, il suo dipendente nome e altri quelli che non dipendono dal parametro T sono indipendenti .
Ecco la regola: il compilatore no cerca in classi di base dipendenti (come A) quando si guarda in modo indipendente nomi (come Vec_t). Di conseguenza, il compilatore non sa nemmeno che esistono e tanto meno sono tipi.
Il compilatore non può presumere che Vec_t
sia un tipo fino a quando non conosce T
perché esiste una potenziale specializzazione di A<T>
dove A<T>:: Vec_t
è a è un membro di dati
Quindi la soluzione è usare typename
typename A<T>::Vec_t v; ← good
Ti consiglio di consultare questo https://isocpp.org/ wiki / faq / templates # nondependent-nome-lookup-tipi .
Vecchio link (non funzionante): http: // www. parashift.com/c++-faq-lite/templates.html#faq-35.18
Perché il compilatore non è sicuro che Vec_t
nomina un tipo. Ad esempio, A<T>
potrebbe essere specializzato per T=int
in non avere quel particolare typedef
.
Per completezza, ecco come è possibile mitigare un po 'questo fastidio:
- riscrive quei tipi in classi derivate, o meglio - come con metodi -
- importa semplicemente quei nomi nell'ambito della classe derivata con un
using declaration
:
template<typename T>
class A
{
public:
typedef std::vector<T> Vec_t;
};
template<typename T>
class B : public A<T>
{
public:
using typename A<T>::Vec_t;
// .........
private:
Vec_t v;
};
Può essere utile se hai più di una menzione dell'ereditato typedef
nella classe derivata. Inoltre non è necessario aggiungere typename
ogni volta con questo.
Devi qualificare esplicitamente l'uso di Vec_t
perché il compilatore non sa da dove proviene <=>.
Non può assumere nulla sulla struttura di A, poiché il modello di classe A può essere specializzato. La specializzazione può includere un <=> che non è un typedef o potrebbe non includere affatto un membro <=>.
Vec_t non è un nome dipendente e il compilatore deve sapere di cosa si tratta senza creare un'istanza di modelli (in questo caso la classe base). Non è davvero diverso da:
template <class T>
class X
{
std::string s;
}
Anche qui il compilatore deve sapere di std :: string anche se X non è istanziato, poiché il nome non dipende dall'argomento template T (per quanto il compilatore possa supporre).
Tutto sommato, i typedef in una classe base del modello sembrano piuttosto inutili per l'uso nella classe derivata. I typedef sono comunque utili per l'utente.
Questo concetto può essere associato al modo in cui usiamo std::vector<T>
. Ad esempio, se abbiamo un std::vector<int> Foo
. Ora, decidiamo di utilizzare uno qualsiasi dei suoi tipi di membri, diciamo un iterator
. In questo scenario menzioniamo esplicitamente
std::vector<int>::iterator foo_iterator;
Analogamente nel tuo caso, per utilizzare un tipo di membro pubblico Vec_t
di template <typename T> class A
, devi dichiararlo esplicitamente come
A<T>::Vec_t v;
OR
A<int>::Vec_t int_type;