2015-05-29 11 views
8

Sono multiple istanze dello stesso modello di classe con lo stesso tipo consentito in diverse unità di compilazione? E i modelli di funzione?Collegamento di istanza modello di classe esplicita

Un codice di esempio è la seguente:

test.hpp

template <typename T> 
class A 
{ 
    public: 
     T out(); 
}; 

template <typename T> 
T A<T>::out() 
{ 
    return T(1); 
} 

test1.cpp

#include "test.hpp" 
template class A<int>; 
int testFn() 
{ 
    return A<int>().out(); 
} 

test2.cpp

#include "test.hpp" 
template class A<int>; 
extern int testFn(); 
int main() 
{ 
    return testFn() == A<int>().out(); 
} 

Se corro

01.235.164,106174 millions
g++ -std=c++11 test1.cpp test2.cpp -o test 

compila senza lamentarsi di definizioni duplicate.

Mi riferivo a vecchie bozze di standard [1] [2] e presupponendo che la parte di collegamento non cambi troppo (tranne che per spazi dei nomi anonimi). Il modello di classe ha un collegamento esterno di 3.5p4 e 14p4. Se questo è il caso, mi aspetto che g ++ debba lamentarsi delle definizioni duplicate di A :: out(). Mi sto perdendo qualcosa qui?

Cosa succede se test.hpp definisce invece un modello di funzione senza "statico" o "in linea"?

Grazie.

[1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf [2] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

+2

[temp.spec] p5 * "Per un determinato modello e un determinato set di argomenti del modello, - una definizione di istanziazione esplicita deve apparire al massimo una volta in un programma [...] Un'implementazione non è necessaria per diagnosticare un violazione di questa regola. "* – dyp

+0

Vedere anche [CWG NAD 1045] (http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_closed.html#1045) che contiene un motivo per cui questo probabilmente non diagnosticati. – dyp

+0

@dyp, In questo caso, il mio programma viola effettivamente 14.7.0.5, ma lo standard dice che g ++ non è richiesto per diagnosticare questo e in realtà g ++ ha risolto la definizione multipla. Ma per renderlo conforme agli standard, dovrei definire tutte le istanze in una sola unità di traduzione e dichiarare ("extern") l'istanziazione di template esplicita in altre unità di traduzione. Ho ragione? – nocte107

risposta

1

Un buon modo per trovare le risposte a queste domande per l'attuazione è quello di utilizzare "nm". Spesso i simboli C++ deformati sono più leggibili se si canalizza l'output di nm in C++ filt.

Ad esempio, se si compila con "-c" per creare ".o" di ciascuna unità di compilazione, è possibile eseguire nm. Quando faccio questo vedo che i membri del template sono simboli deboli "W" (su x86 linux). Ciò significa che più definizioni sono ok e in qualche modo specifico del sistema. Se creo una funzione che non è templata, apparirà come una "T" in entrambe le unità di traduzione corrispondenti ai file oggetto. Ciò causerà un simbolo definito più.

In genere i modelli C++ vengono istanziati in base alle esigenze (senza una creazione completa) che consentono di utilizzare un'intestazione di tipo _impl oltre all'intestazione della dichiarazione.

Non è possibile definire un modello membro come statico (che genera un errore). Puoi definirlo come inline. In tal caso, non vedrai nessun simbolo per il modello membro utilizzando nm, perché è stato inarcato.

+0

Nella tua risposta hai citato "in qualche modo specifico del sistema". Significa che non è specificato dallo standard e potrebbe non essere portatile? Per quanto riguarda la mia ultima domanda sui modelli di funzione, intendo modelli di funzioni più generali piuttosto che modelli di funzioni di membri di classi. Grazie. – nocte107