持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
模版的具体化
模版的具体化,则是根据特定的模版参数,给出不同的定义。例如,下面这个函数模版想要获取一些类型的长度:
template <typename T>
void printlen(T t) {
cout << t.size() << endl;
}
这样的函数可以对vector、string等类型有效,但对于char类型的字符串却无法通过编译。如果我们想让这个函数支持char,则需要对char*类型单独给出一个定义:
template <>
void printlen(char* t) {
cout << strlen(t) << endl;
}
其实模板的具体化和函数的重载类似,相当于重载了一个同名的函数。在调用这个函数模版时,对于char*类型的参数,会优先调用这个具体化的函数。函数模板的具体化也是实例化,它是一个真正的函数。
模版的编译期语法检查
正因为类模版与函数模版本身并不是类或者函数,所以很多语法校验在模版定义中没办法做,只有在为模版确定了类型之后,生成了真正的类或函数实例,才能做语法检查。生成真正的实例,也叫做模版的实例化。
例如下面这段代码:
template <typename T>
void func(T t) {
cout << t.size() << endl;
}
int main() {
string str = "abc";
func(str); // 等价于 func<string>("abc"); 正常编译
func(1); // 编译错误
}
函数模版中调用t的size()方法,但模版的声明中并没有限制T必须有size()方法,事实上C++的模版也没办法做这样的限制。当调用func时,传入的T是string时,不会有编译问题,但如果传入的是int,则会有编译错误。编译器具体是怎么做的呢?
实际上,如果没有显示的实例化,函数模版只有在有调用时才会根据需要进行实例化。如果代码中有调用func并传入了string类型的参数,则会生成T为string类型的func(string t)函数实例,当传入int类型时,则会将T作为int类型,实例化出func(int)函数。
而func(int)函数实例化之后,编译这个函数就会出现错误,因为int类型没有size()方法。