2013-06-04 26 views
7

Próbuję uzyskać dostęp do statycznej funkcji członka zdefiniowanej w szablonie klasy. W TemplateTest.h pliku nagłówka I zdefiniowany szablon klasy podstawowej jak:Funkcja elementu statycznego wewnątrz specjalizacji szablonów klasy

#include<iostream> 

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

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

    }*/ 
}; 

Następnie Plik źródłowy TemplateTester.cpp kładę specjalność:

#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 

jawnie instancję klasy z tak łącznikowych ustąpieniu prawidłowo.

W driver.cpp Kierowca:

include "TemplateTest.h" 

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

Kiedy skompilować TemplateTest.cpp z g ++ generuje plik obiektowy poprawnie, ale gdy próbuję połączyć go z klasy sterownika daje mój błąd łącznik " undefined odwołanie do `TemplateTest :: invoke()"

Przeszedłem przez inne podobne posty, takie jak this one, ale nie próbuję uzyskać dostęp do szablonu funkcji.

Każda wskazówka jest bardzo cenna.

+4

Przenieś implementację do pliku nagłówkowego. Implementacje szablonów muszą być widoczne dla wszystkich JT korzystających z nich. –

Odpowiedz

5

Masz rację, że plik utworzyć obiekt z TemplateTester.cpp będzie zawierać symbol specjalizacji, który podałeś. Dzieje się tak, ponieważ każda jawna specjalizacja powoduje, że szablon jest tworzony, i jest to podwójnie ważne, ponieważ dodano nawet instancję jawną (która w rzeczywistości jest niepotrzebna).

Jednak w momencie kompilowania driver.cpp kompilator nie wie o specjalizacji, ponieważ zawiera tylko TemplateTester.h, a specjalizacja nie jest tam wspomniana. Tak więc kompilator tworzy szablon, oczywiście nie używając specjalnej definicji, więc masz problem.

Standard mówi Kursywa (przeze mnie):

(§14.7.3/6) Jeśli szablon, szablon członkowski lub członek szablonu klasy jest wyraźnie wyspecjalizowany, specjalizacja ta powinna zostać zadeklarowana przed pierwszym użyciem tej specjalizacji, co spowodowałoby utworzenie niejawnego wystąpienia, w każdej jednostce tłumaczeniowej w w którym takie użycie występuje; diagnostyka nie jest wymagana. Jeśli program nie zapewnia definicji specjalizacji jawnej, a specjalizacja jest wykorzystywana w sposób, który spowodowałby niejawne utworzenie wystąpienia lub członek jest funkcją wirtualnego elementu, program jest źle sformułowany, nie jest wymagana diagnostyka. Natychmiastowe tworzenie instancji nigdy nie jest generowane dla jawnej specjalizacji, która jest zadeklarowana, ale nie jest zdefiniowana. [...]

Musisz więc podać zarówno deklarację, jak i definicję specjalizacji znaną kompilatorowi, gdy działa ona pod numerem driver.cpp. Najlepszym sposobem na to jest dodanie całej specjalizacji do TemplateTester.h.

Należy ponownie zauważyć, że jawne tworzenie instancji nie jest faktycznie wymagane.

+1

Dzięki za wyjaśnienie @jogojapan. Jest to właściwie prototyp biblioteki statycznej szablonu, nad którą pracuję. Teraz widzę, dlaczego to się nie udaje Myślę, że mogę przenieść definicje, aby kompilator był szczęśliwy. – jazaman

3

Istnieje kilka problemów:

  • nie trzeba jawnie instancji w pełni wyspecjalizowanych szablon
  • jeśli chcesz umieścić swoje metody statycznej w nagłówku, a następnie użyć inline. W przeciwnym wypadku dostaniesz wiele wystąpień i problemów linkera
  • szablon specjalizacje można umieścić w nagłówku, a określenie metod w plikach źródłowych
  • jeśli nie chcesz coś nazwać w szablonie, nie trzeba definiować to. Dostaniesz błędy kompilatora, a to oznacza wcześniejsze wychwytywanie błędów.

// 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(); 
} 

Innym sposobem jest zmiana nagłówka, a następnie dodaj plik źródłowy.

// 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

Dzięki @ BЈовић Próbowałem wymyślić tutaj prototyp. Być może powinienem wyraźnie o nich wspomnieć. Szablony klas są w rzeczywistości częścią biblioteki statycznej i dlatego nadal potrzebuję instancji. Ale masz rację, nie powinienem definiować funkcji wewnątrz klasy. Powinno to być zrobione na zewnątrz. Spróbuję tego i zobaczę, czy to rozwiąże mój problem. – jazaman

+0

@jazaman Nie, nie trzeba tworzyć instancji w pełni wyspecjalizowanych szablonów, ponieważ są one jak normalne (nie-szablonowe) klasy. Jeśli umieścisz swój nagłówek w kilku miejscach, otrzymasz błędy linkera. –

+0

po przeczytaniu drugiej odpowiedzi Rozumiem, że jeśli jest to w pełni wyspecjalizowany przypadek, nie trzeba już tego robić. – jazaman