2011-09-29 75 views
0

我有一個類基地base.h,它具有一個模板函數鏈接問題,當派生的類調用基類的模板函數

class Base { 
template <typename T> void test(T a); 
} 

該模板被認爲在intdouble類型閱讀,和我有類派生,這是從類基地派生

我試圖調用類導出的功能測試,但我有鏈接錯誤。

最後,我意識到,如果在base.cpp,我添加

void test(int a); 
void test(double a); 

不會有編譯器錯誤。這個解決方案看起來很尷尬,有沒有更好的解決方案?謝謝

+0

發佈更多代碼。你怎麼稱呼它?什麼是錯誤? – Nawaz

+0

我沒有問題。模板函數是否在頭文件中聲明瞭_and_? – sje397

+0

通常,閱讀編譯器錯誤消息可以提供有用的信息,幫助您瞭解問題所在。 – Hugh

回答

3

C++模板必須是定義(給出了完整的函數體)在相同的翻譯單元(.cpp文件中加所有包含的頭文件)在哪裏使用。在你的頭文件中,你所做的全部是,聲明爲(給出了函數的名字和簽名)。其結果是,當你有base.h,所有的編譯器看到的是:

class Base { 
    template <typename T> void test(T a); 
} 

此聲明,但沒有定義的功能。要定義它,你必須包含一個函數體:

class Base { 
    template <typename T> void test(T a) 
    { 
    // do something cool with a here 
    } 
} 

爲什麼這是必需的是,C++編譯器生成基於「按需」基礎模板代碼的原因。例如,如果您撥打:

Base obj; 
obj.test<int>(1); 
obj.test<char>('c'); 

編譯器將基於該Base::test模板兩套機器代碼,一個用於int和一個用於char。此處的侷限性是Base::test模板的定義必須位於相同的翻譯單元(.CPP文件)中,否則編譯器將不知道如何爲Base::test函數的每個版本構建機器碼。編譯器一次只能在一個翻譯單元上運行,因此不知道您是否在其他某個CPP文件中定義了Base::test<T>。它只能用它現有的東西來工作。

這與泛型在C#,Java和類似語言中的工作方式截然不同。就我個人而言,我喜歡將模板視爲文本宏,並由編譯器根據需要進行擴展。這迫使我記住,模板函數的完整主體需要包含在使用它的任何CPP文件中。

+0

說實話,他們不需要**在頭文件中定義* always *,只有這樣*隱式實例化才能工作。 OP已經意識到它可以在單個翻譯單元中,但它強制用戶*手動實例化模板'模板void Base :: test ();' - 通常不值得麻煩。 –

2

在可以使用之前,您必須完全定義模板函數test。要做到這一點,最簡單的方式就是寫你的函數體在頭中base.h

class Base { 
template <typename T> void test(T a) 
{ 
    ... function body here 
} 
} 
0

如果您在基類中聲明瞭模板函數,這意味着它在編譯時需要模板參數,但是如果您嘗試通過派生類訪問,這是運行時實現,所以在編譯時模板請求不能在運行時提供,主要的事情C++不支持這一點。

相關問題