1.6 模板的编译

模板的编译一般采用包含编译,(其他比较偏门的会介绍export啥的),export已经被废止了,所以不再去研究。

正确的做法是:

  • 模板的实现都放到.h也就是头文件里面
  • 使用的时候直接包含头文件

在链接阶段,如果是因为模板生成的代码,比如类定义或者函数义有多份,那么会自动去重。

嵌套类型依赖

假设想使用T类里面的iterator,如果代码写做如下:

template<typename T>
void print2nd(const T& container)
{
T::const_iterator * x;
...
}

由于编译器并不清楚const_iterator是一个类型,还是静态变量,大多数情况下会认为是一个静态变量。但是,这里实际上是一个类型,所以这里会编译报错。

那么正确的写法应该是

template<typename T>
void print2nd(const T& container)
{
typename T::const_iterator *x;
...
}

也就是说,在嵌套类型依赖的时候,需要明确的指出typename这个类型。

例外

只有2个地方是不需要在嵌套依赖的时候来指明typename的,那么就是声明继承的时候。

template<typename T>
class Derived: public Base<T>::Nested // 1. 这里不需要
{
 public:
  explicit Derived(int x)
  : Base<T>::Nested(x) // 2. 这里也不需要
  {
   typename Base<T>::Nested temp; //nested dependent type, need typename
  }
};

比如,这里Nested就是Base<T>里面的一个类型。实际上,这里也很明显,那就是继承肯定是继承于类型,而不是一个静态变量。

类中的模板函数

template<typename T>
class aTMP{
public:
typedef const T reType;
};
void f() {
std::cout << "global f()" << std::endl;
}
template<typename T>
class Base {
public:
template<int N = 99> // 这里需要声明模板函数
void f() {
std::cout << "member f(): " << N << std::endl;
}
};

this指针

this 用于指定查找基类中的成员

  • (当基类是依赖模板参数的类模板实例时,由于实例化总是推迟,这时不依赖模板参数的名字不在基类中查找,文献[1]第 166 页)
#include <iostream>
template<typename T>
class aTMP{
public: typedef const T reType;
};
void f() { std::cout << "global f()\n"; }
template<typename T>
class Base {
public:
template <int N = 99>
void f() { std::cout << "member f(): " << N << '\n'; }
};
template<typename T>
class Derived : public Base<T> {
public:
typename T::reType m; // typename 不能省略
Derived(typename T::reType a) : m(a) { }
void df1() { f(); } // 调用全局 f(),而非想象中的基类 f()
void df2() { this->template f(); } // 基类 f<99>()
void df3() { Base<T>::template f<22>(); } // 强制基类 f<22>()
void df4() { ::f(); } // 强制全局 f()
};
int main(){
Derived<aTMP<int>> a(10);
a.df1(); a.df2(); a.df3(); a.df4();
std::cin.get(); return 0;
}