2010-04-29 11 views
10

Vedere il seguente codice e si prega di chiarire i miei dubbi.In che modo le istanze dei modelli esplicite influiscono su ciò che il linker può trovare?

  1. Come ABC è un modello, perché essa non mostra un errore quando abbiamo messo la definizione della funzione di membro di classe ABC in test.cpp?

  2. Se inserisco il codice test.cpp in test.h e lo rimuovo 2, funziona correttamente. Perché?

.

// test.h 
template <typename T> 
class ABC { 
public: 
    void foo(T&); 
    void bar(T&); 
}; 
// test.cpp 
template <typename T> 
void ABC<T>::foo(T&) {} // definition 
template <typename T> 
void ABC<T>::bar(T&) {} // definition 

template void ABC<char>::foo(char &); // 1 
template class ABC<char>;    // 2 
// main.cpp 
#include "test.h" 
int main() { 
    ABC<char> a; 
    a.foo();  // valid with 1 or 2 
    a.bar();  // link error if only 1, valid with 2 
} 
+0

Perché me lo chiedi? Sono due affermazioni piuttosto indipendenti. –

+0

@Dennis Zickefoose: eravamo tutti principianti ad un certo punto – ereOn

+0

@ereOn: Sì, ma il motivo per cui sta chiedendo può fare molto per suggerire un approccio corretto da adottare quando si risponde alla sua domanda. –

risposta

13

In entrambi i casi si sta eseguendo un'istanza esplicita. Nel secondo caso, viene istanziato solo ABC<char>::foo, mentre nel primo caso viene anche istanziato ABC<char>::bar.

Un diverso esempio simile può chiarire le implicazioni:

// test.h 
template <typename T> 
class ABC { 
public: 
    void foo(T&); 
    void bar(T&); 
}; 
// test.cpp 
template <typename T> 
void ABC<T>::foo(T&) {} // definition 
template <typename T> 
void ABC<T>::bar(T&) {} // definition 

template void ABC<char>::foo(char &); // 1 
template class ABC<char>;    // 2 
// main.cpp 
#include "test.h" 
int main() { 
    ABC<char> a; 
    a.foo();  // valid with 1 or 2 
    a.bar();  // link error if only 1, valid with 2 
} 

Nell'esempio, in main il compilatore non può vedere foobar definizioni, quindi non può istanziare i metodi. Il compilatore, durante l'elaborazione di main.cpp accetterà il codice in main volentieri, dal momento che stai dicendo che ABC è un modello e che ha queste due funzioni e assumerà che saranno definite in qualche altra unità di traduzione.

Nell'unità di traduzione che contiene test.cpp il compilatore sta visualizzando entrambe le definizioni di metodo e entrambe le istanze (metodo/classe) possono essere completamente elaborate. Se è presente solo l'istanza del metodo ([1]), il compilatore genererà tale metodo e lascerà bar indefinito. Pertanto, qualsiasi codice che includa test.h, i collegamenti con il test.cpp compilato e utilizzi solo il metodo foo verranno compilati e collegati, ma l'utilizzo di bar non riuscirà a collegarsi a causa del fatto che non è definito.

L'istanziazione esplicita del modello di classe genera i simboli per tutti i metodi membro e, in tal caso, qualsiasi unità di traduzione che include test.h e collegamenti al file oggetto test.cpp compilato verrà compilata e collegata.

+0

ho due dubbi 1. come ABC è modello perché non mostra errore quando inseriamo la definizione della funzione membro della classe ABC in test.cpp 2.se inserisco il codice test.cpp in test.h e rimuovo 2 poi funziona per favore, puoi spiegare – Suri

+0

Le definizioni dei metodi di modello non devono necessariamente trovarsi all'interno del corpo della classe, anche se è raccomandato. Come con le funzioni regolari, se il compilatore vede solo la dichiarazione del metodo, assumerà che sia definito da qualche altra parte, come nell'esempio in cpp. Questo approccio è problematico in quanto si limitano i tipi che possono essere utilizzati con il proprio modello a quelli per i quali si fornisce una specializzazione esplicita. Questo può essere usato per accelerare il tempo di compilazione per codice fortemente basato su modelli per il quale tutti i tipi che istanziano il modello sono noti in anticipo. –

+0

Nella seconda domanda, se si spinge tutto il codice insieme, il compilatore vede la definizione del modello (metodo), quindi quando si chiama il metodo 'bar' all'interno di main si eseguirà un'istanza implicita di quel metodo. Si noti che l'istanziazione esplicita è richiesta solo se il compilatore non può istanziare implicitamente il modello e che nella maggior parte dei casi se il compilatore ha abbastanza informazioni, permettendo di decidere quali metodi istanziare (solo quelli usati) si miglioreranno i tempi di compilazione (e intermedi) file oggetto, anche se nella maggior parte dei casi il linker può scartare i simboli inutilizzati) –

0

(Questa è una versione modificata della mia risposta originale, richiesto dal osservazione di David Rodriguez.)

#1 un'istanza della classe template, e come parte di che crea un'istanza tutti i suoi metodi.

#2 istanzia un metodo membro della classe. Come parte di ciò, deve istanziare il modello di classe, ma non tutti i suoi altri metodi.

La differenza può essere vista se si introduce un errore dipendente dal tipo in bar() (ad esempio un'istruzione come void *x = b;). Otterrai un errore del compilatore con #1 ma non con #2. Si noti inoltre che il compilatore (gcc almeno) non compilerebbe #1 seguito da #2, ma compilerebbe uno di essi senza l'altro, o se #2 è stato seguito da #1.

+0

Quando si istanziano i modelli di classe, solo i membri effettivamente _used_ vengono istanziati. Ecco perché ti credo che il n. 2 sia sbagliato. La risposta di David dice anche così. – sbi

0

Immagino che volessi avere {} al posto di; in 1.

Problemi correlati