上一篇:《深入理解C++11》笔记–扩展
本篇介绍第二章最后一部分内容,模板相关的扩展。
- 模板函数的默认模板参数
- 外部模板
- 局部和匿名实参作为模板参数
模板函数的默认模板参数
大家都了解函数可以拥有默认形参,并且模板类可以有默认的模板参数,现在C++11中模板函数也可以有默认的模板参数了。例如:
template<typename T = int> // C++98、C++11都能编译通过
class Testclass{
};
template<typename T = int> // C++11编译通过
void test_fun(){}
模板函数的默认参数和模板类的默认参数有一点不同,模板类的默认参数必须从右到左,但是模板函数不比如此。
template<typename T1 = char, typename T2> // 不能编译通过
class Testclass{
};
template<typename T1 = char, typename T2> // 可以编译通过
void test_fun()
{
}
外部模板
外部指的就是extern修饰符,原来就一直有外部变量的概念。外部变量是为了防止同名的变量分别定义在不同的文件中时,在两份文件的数据区中产生两个相同名字的变量,其他文件同事调用这两个文件时,链接的时候会产生误解,无法成功链接。而在其中一个文件的声明时使用了extern修饰符,就会认为这个变量是一个外部的变量,不会再去生成数据区中的数据。
外部模板也是为了避免类似的问题,例如下面这段代码,在两个文件中分别使用了同一个模板函数的同一个类型,这样在编译的时候会分别生成相同两份代码,链接过程中链接器会自动删除多余的重复代码,这样就增加了编译时间。
//test.h
template<typename T>
void test_fun(T a)
{
}
//test1.cpp
test_fun(1);
//test2.cpp
test_fun(2);
这个问题可以用外部模板来避免,修改test1.cpp和test2.cpp的内容如下,先对模板进行显示实例化,然后在相同模板类型的调用处使用extern进行修饰。
//test1.cpp
template void test_fun<int>(int);
test_fun(1);
//test2.cpp
extern template void test_fun<int>(int);
test_fun(2);
局部和匿名实参作为模板参数
C++11同时支持了局部和匿名的类型作为模板参数,如下:
template<typename T>
class Testclass
{
};
template<typename T>
void test_fun(T a)
{
}
struct A{}a; // 命名类型
struct{int i;} b; // 匿名类型变量
typedef struct{int i;} B; // 匿名类型
int main()
{
struct C{} c; // 局部命名类型
Testclass<A> test1; // C++98、C++11都编译通过
Testclass<B> test2; // C++11编译通过
Testclass<C> test3; // C++11编译通过
test_fun(a); // C++98、C++11都编译通过
test_fun(b); // C++11编译通过
test_fun(c); // C++11编译通过
return 0;
}