发布
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>,因此我们显式地要求编译器为这些
两种类类型的所有的可实例化部分生成代码。
请注意实例化指令的编写方式。
我们现在可以成功地编译和链接我们的代码。

我们还可以显式地实例化模板函数,或单个模板类成员函数。