c++的模板类

起因

昨天帮一个同学debug一个问题,想想也是醉了,太久没写C++,报错信息都看着陌生,还好有万能的Google,让我从stackoverflow中找到了答案。

开始讲故事

C++标准库的书中,曾经说过这么一句话

唯一一种方便的使用模板类的方法是用内联函数的方式在头文件中一次性实现。

为什么呢?

对于一个模板类,编译器在实例化的时候,通过模板类的参数,会创建一个新的类,举个例子:

1
2
3
4
5
6
7
8
9
template<typename T>
struct Foo
{
T bar;
void doSomething(T param) {}
};

// somewhere in a .cpp
Foo<int> f;

当编译器读到下面这一行的时候,就会创建一个新的类,我们可以把它叫做FooInt,这个类的实现等价于下面这种模式:

1
2
3
4
5
struct FooInt
{
int bar;
void doSomething(int param) {}
}

因此,编译器开始需要去实现里面类的方法,自然是通过模板的参数来实现它们。如果这些实现不在头文件里面,编译器就无法获取到这些模板,自然就无法实现模板类的方法了。


方法:

当然,将函数的声明和实现放在多个文件中,有时候是非常有必要的,简洁,条理,或者强迫症。。。
一种简单的解决方案是在头文件中声明类的方法之后,把类的实现写在文件B中,然后再头文件中include文件B,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 在Foo.h中声明;
template <typename T>
struct Foo
{
void doSomething(T param);
};
//include 实现的文件;
#include "Foo.tpp"

// 在Foo.tpp中实现函数;
template <typename T>
void Foo<T>::doSomething(T param)
{
//implementation
}

哈哈,这是一种十分取巧的方法,不过也达到了目的,而且效果拔群。
还有一种方法,感觉上就不是很推荐了,但是更加正常一些。

1
2
3
4
5
6
7
8
9
// Foo.h
// no implementation
template <typename T> struct Foo { ... };

// Foo.cpp
// implementation of Foo's methods
// explicit instantiations
template class Foo<int>;
template class Foo<float>;

这种方法就是在cpp文件中,实现的模板类的函数之后,在文件中同时将你想要使用的模板参数,明确的实例化出来。

本人还是比较喜欢第一种,毕竟

1.我不喜欢一个模板类实现在一个文件里,过长的文件真得太受不了了。
2.第二种方法也就必须把所有的模板类函数实现在一个文件里!

博文翻译于stackoverflow.

TODO:

可以看下答主推荐的文章