2013-06-04 21 views
7

Non riesco ad accedere alla funzione membro statica definita all'interno del modello di classe. Nel file di intestazione TemplateTest.h ho definito il modello di classe primaria come:all'interno della specializzazione del modello di classe

#include<iostream> 

template<class T, class U> 
struct TemplateTest 
{ 
public: 
    void static invoke(); 
    /*{ 

     std::cout << "Should not be called" << std::endl; 

    }*/ 
}; 

Poi origine del file TemplateTester.cpp ho messo una specializzazione:

#include "TemplateTest.h" 

template<> 
struct TemplateTest<int, bool> 
{ 
    static void invoke() 
    { 
     std::cout << "invoke<int, bool>" << std::endl; 
    } 
}; 

template struct TemplateTest<int, bool>; //instantiate to resolve linker issue 

ho istanziate esplicitamente la classe con risolve così linker correttamente.

Nella driver.cpp conducente:

include "TemplateTest.h" 

int main() 
{ 
    TemplateTest<int, bool>::invoke(); 
    return 0; 
} 

Quando compilo il TemplateTest.cpp con g ++ genera il file oggetto correttamente, ma quando provo a collegarlo alla classe conducente si dà il mio errore di linker " riferimento non definito a `TemplateTest :: invoke()"

Sono passato attraverso altri post correlati come this one ma non sto tentando di accedere a un modello di funzione.

Qualsiasi indizio è molto apprezzato.

+4

Spostare l'implementazione nel file di intestazione. le implementazioni del modello devono essere visibili a tutte le TU che le utilizzano. –

risposta

5

Hai ragione che il file oggetto creato da TemplateTester.cpp conterrà un simbolo per la specializzazione che hai fornito. Questo perché le specializzazioni esplicite fanno sì che il template sia istanziato, ed è doppiamente il caso perché hai persino aggiunto un'istanza esplicativa (che in realtà non è necessaria).

Tuttavia, al momento della compilazione di driver.cpp, il compilatore non conosce la specializzazione, poiché include solo TemplateTester.h e la specializzazione non è menzionata lì. Quindi il compilatore istanzia il modello, ovviamente non utilizzando la definizione specializzata, in modo da ottenere il tuo problema.

Lo Standard dice (corsivo da me):

(§14.7.3/6) Se un modello, un modello membro o un membro di un modello di classe è esplicitamente specializzato, tale specializzazione deve essere dichiarata prima del primo utilizzo di quella specializzazione che causerebbe un'istanza implicita, in ogni unità di traduzione in quale tale uso si verifica; non è richiesta alcuna diagnostica. Se il programma non fornisce una definizione per una specializzazione esplicita e la specializzazione viene utilizzata in un modo che causerebbe un'istanza implicita o se il membro è una funzione membro virtuale, il programma è mal formato, non è richiesta alcuna diagnostica. Un'istanza implicita non viene mai generata per una specializzazione esplicita dichiarata ma non definita. [...]

Quindi è necessario fare sia, la dichiarazione e la definizione della specializzazione noto al compilatore quando si lavora su driver.cpp. Il modo migliore per farlo è aggiungere l'intera specializzazione a TemplateTester.h.

Nota, ancora una volta, che un'istanza esplicativa esplicita non è effettivamente richiesta.

+1

Grazie per la spiegazione @jogojapan. Questo è in realtà un prototipo di libreria statica di modelli su cui sto lavorando. Ora capisco perché sta fallendo suppongo di poter spostare le definizioni per mantenere il compilatore felice. – jazaman

3

Ci sono diversi problemi:

  • non è necessario creare un'istanza in modo esplicito modello completamente specializzata
  • se si vuole mettere il metodo statico nell'intestazione, quindi utilizzare inline. In caso contrario, riceverai più istanze e problemi di linker
  • specializzazioni di modelli che inserisci nell'intestazione e definisci metodi nei file di origine
  • se non vuoi che venga chiamato qualcosa in un modello, non è necessario definire esso. Otterrai errori del compilatore e ciò significa rilevare gli errori in precedenza.

// TemplateTest.h 
#include<iostream> 

template<class T, class U> 
struct TemplateTest; 
template<> 
struct TemplateTest<int, bool> 
{ 
    inline static void invoke() 
    { 
     std::cout << "invoke<int, bool>" << std::endl; 
    } 
}; 

// main.cpp 
include "TemplateTest.h" 

int main() 
{ 
    TemplateTest<int, bool>::invoke(); 
} 

Un altro modo è quello di cambiare l'intestazione, e aggiungere il file sorgente.

// TemplateTest.h 
#include<iostream> 

template<class T, class U> 
struct TemplateTest; 

template<> 
struct TemplateTest<int, bool> 
{ 
    static void invoke(); 
}; 

// TemplateTest.cpp 
#include "TemplateTest.h" 
void TemplateTest<int, bool>::invoke() 
{ 
    std::cout << "invoke<int, bool>" << std::endl; 
} 
+0

Grazie @ BЈовић In realtà ho cercato di venire qui con un prototipo. Forse dovrei menzionarli esplicitamente. I modelli di classe fanno effettivamente parte di una libreria statica e quindi, penso che avrei ancora bisogno dell'istanza. Ma hai ragione, non dovrei definire la funzione all'interno della classe. Dovrebbe essere fatto fuori. Lo proverò e vedrò se risolve il mio problema. – jazaman

+0

@jazaman No, non è necessario creare istanze di modelli completamente specializzati, poiché sono come normali classi (non template). Se includi l'intestazione in più punti, otterrai degli errori di linker. –

+0

dopo aver letto l'altra risposta capisco che se è un caso completamente specializzato non è più necessario farlo. – jazaman