釋出
2009年9月11日

模板例項化

評分:3.5/5 (11 票)
*****
模板例項化

我一直在尋找一些可以寫一篇小文章的東西
這似乎是個不錯的選擇。
論壇上有很多關於這個問題的帖子,作者將
模板拆分為 *.h 檔案和 *.cpp 檔案,並遇到連結器
問題。
通常給出的答案是將所有模板內容放入 *.h 檔案中
因為必須這樣做。
類/函式。
這並不完全正確。
C++ 有隱式模板例項化和顯式例項化

隱式例項化
template.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#ifndef TEMPLATE_H
#define TEMPLATE_H

#include <iostream>

template <typename T>
class myTemplate
{
  private:
  T data;
 
  public:
  myTemplate();
  myTemplate(T t);
  T getData() const;
  void displayData() const;
  
  static int someValue; 
};
  
template<typename T>
myTemplate<T>::myTemplate()
:data()
{
}

template<typename T>
myTemplate<T>::myTemplate(T t) 
:data(t)
{
}

template <typename T>
T myTemplate<T>::getData() const
{
    return data;
}

template <typename T>
void myTemplate<T>::displayData() const
{
    std::cout << data <<std::endl;
}


template<typename T>
int myTemplate<T>::someValue = 100;

#endif 


在 main.cpp 中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include "template.h"

using namespace std;

int main()
{
    myTemplate<int> myTi(5);  
    myTi.displayData();
    
    myTemplate<float> myTf(3.5f);
    myTf.displayData();
      
    return 0;
}


在上面的示例中,完整的模板定義位於標頭檔案中
main.cpp 包含該標頭檔案 - 因此在編譯
和連結過程中不會出現問題。
如果我們忘記定義 displayData() 函式
那麼我們會收到連結器錯誤,而不是編譯器錯誤。

//=========================================================================================//
顯式例項化 假設我們要將模板類拆分為標頭檔案和原始檔。
所以我們有 main.cpp 和 template.cpp。
我們編譯這兩個檔案,但會收到連結器錯誤,因為 template.cpp
檔案中的實際程式碼未被例項化。
要使編譯器例項化所需的程式碼,我們可以使用顯式例項化。

template.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef TEMPLATE_H
#define TEMPLATE_H

#include <iostream>

template <typename T>
class myTemplate
{
  private:
  T data;
 
  
  public:
  myTemplate();
  myTemplate(T t);
  T getData() const;
  void displayData() const;
  
  static int someValue;
  
};
  
#endif 

template.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "template.h"
#include <iostream>


//template functions 
template<typename T>
myTemplate<T>::myTemplate()
:data()
{
}

template<typename T>
myTemplate<T>::myTemplate(T t) 
:data(t)
{
}

template <typename T>
T myTemplate<T>::getData() const
{
    return data;
}

template <typename T>
void myTemplate<T>::displayData() const
{
    std::cout << data <<std::endl;
}


template<typename T>
int myTemplate<T>::someValue = 100;


//The explicit instantiation part
template class myTemplate<int>; 
template class myTemplate<float>;


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

#include "template.h"

using namespace std;


int main()
{

    myTemplate<int> myTi(5);
    
    myTi.displayData();
    
    myTemplate<float> myTf(3.5f);
    myTf.displayData();
  
    return 0;
}


重要的部分是 template.cpp 中的最後幾行。我們知道我們需要一個 myTemplate<int> 和一個 myTemplate<float>,因此我們顯式地要求編譯器為這些
兩種類型別的所有的可例項化部分生成程式碼。
請注意例項化指令的編寫方式。
我們現在可以成功地編譯和連結我們的程式碼。

我們還可以顯式地例項化模板函式,或單個模板類成員函式。