2013-06-04 151 views
7

我很努力地訪問類模板中定義的靜態成員函數。 在頭文件TemplateTest.h我定義的主類模板爲:類模板專業化中的靜態成員函數

#include<iostream> 

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

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

    }*/ 
}; 

然後源文件TemplateTester.cpp我把專業化:

#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 

我明確實例化的類有這麼鏈接器解析正確。

在驅動程序driver.cpp:

include "TemplateTest.h" 

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

當我編譯克TemplateTest.cpp ++它正確生成目標文件,但是當我嘗試將其鏈接到驅動程序類它給我的鏈接錯誤「未定義引用到`TemplateTest :: invoke()「

我經歷了其他相關的帖子,如this one,但我沒有試圖訪問函數模板。

任何線索都非常感謝。

+4

將實現移動到頭文件。模板的實現需要對所有使用它們的TU都可見。 –

回答

5

你是對的,你從TemplateTester.cpp創建對象文件將包含您所提供的專業化的象徵。情況就是這樣,因爲任何明確的特殊化都會導致模板被實例化,而且這種情況更是如此,因爲您甚至添加了顯式實例化(實際上並不需要)。

但是,在編譯driver.cpp時,編譯器不知道專業化,因爲您只包含TemplateTester.h,並且專業化在那裏沒有提及。所以編譯器實例化了這個模板,當然沒有使用專門的定義,所以你得到了你的問題。

標準說(由我斜體):

(§14.7。3/6)如果一個模板,一個成員模板或一個類模板的成員是明確專門化的,那麼在該專業化的第一次使用之前,該專業化應該在每個翻譯單元中進行隱式實例化,這種用途發生了;不需要診斷。如果程序沒有提供顯式專門化的定義,並且專門化的使用方式可能會導致隱式實例化或成員是虛擬成員函數,那麼該程序不合格,不需要診斷。對於已聲明但未定義的顯式特化,永遠不會生成隱式實例化。 [...]

因此,您需要同時製作編譯器在driver.cpp上工作時已知的專用化的聲明和定義。這樣做的最好方法是將整個專業化添加到TemplateTester.h

再次請注意,顯式實例化實際上並不需要。

+1

感謝您的解釋@jogojapan。這實際上是我正在處理的模板靜態庫的原型。現在我明白了爲什麼它會失敗我想我可以移動定義來保持編譯器的快樂。 – jazaman

3

有幾個問題:

  • 你不需要顯式實例完全專用的模板
  • ,如果你想要把你靜態方法在頭部,然後用inline。否則,你會得到多個實例和鏈接器問題
  • 模板專業化,你放在標題中,並定義源文件中的方法
  • 如果你不想在模板中調用某些東西,你不需要定義它。你會得到編譯器錯誤,這意味着更早發現錯誤。

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

的另一種方法是改變報頭,並添加源文件。

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

Thanks @BЈовић我實際上試圖在這裏想出一個原型。可能是我應該明確地提到他們。類模板實際上是靜態庫的一部分,因此,我認爲我仍然需要實例化。但你是對的,我不應該在課堂上定義函數。它應該在外面完成。我會試試看看它是否能解決我的問題。 – jazaman

+0

@jazaman不,你不需要實例化完全專用的模板,因爲它們就像普通(非模板)類。如果你在幾個地方包含你的頭文件,你會得到鏈接器錯誤。 –

+0

在閱讀了其他答案後,我明白,如果它是完全專業的情況下,不需要再做。 – jazaman