15 Aug 2017
C++11特性介绍——模板相关
模板别名
在C++ 我们经常使用typedef
为类型定义别名, 遇到一些较长类型名字, 尤其在使用模板和域的时候, 使用别名的优势更加的明显;
在C++ 11中, 定义别名已经不是typedef
的专属能力了, 也可以使用using
来完成; 如下:
//使用using 定义别名
using uint = unsigned int;
typedef unsigned int UINT;
std::cout << is_same<uint, UINT>::value << std::endl; //output: 1
在模板编程的时候, using
的语法甚至比typedef
更加灵活, 使用typedef则很难达到这种效果:
template<typename T>
using MapString = std::map<T, char*>;
MapString<int> num_strings;
带默认参数的模板
C++ 11中引入了类似于函数默认形参的样式的,带默认参数的模板; 使用如下:
/*
* 模板函数的默认模板参数
*/
template<typename T1, typename T2 = int>
class DefClass1;
template<typename T1 = int, typename T2>
class DefClass2; //编译错误
template<typename T, int i = 0>
class DefClass3;
template<int i = 0, typename T>
class DefClass4; //编译错误
template<typename T1 = int, typename T2>
void DefFunc(T1 a, T2 b);
template<int i = 0, typename T>
void DefFunc(T a);
说明:
- 类模板的默认参数必须按照从右往左定义(如上);
- 对于带默认参数的函数模板,默认参数位置随意;
外部模板
问题:
同一个函数模板,如果在两个文件中使用即实例化,编译器会对每一文件实例化一份,产生大量的冗余代码,而且在链接的时候,链接器会通过一些编译器辅助手段将重复实例化的代码删掉,会增加编译器的编译时间和连接时间;
解决:
解决方法如同使用外部变量(extern)一样;显示的实例化再加外部模板声明就可以很好地解决这一问题,
例如:对以下模板:
template <typename T> void fun(T) {}
我们只需要声明:
template void fun<int> (int);
这样编译器就会在本编译单元实例化出一个fun<int>(int)
版本的函数。C++ 11中又加入了外部模板的声明,语法如下:
extern template void fun<int> (int);
外部模板的使用如下方式如下:
在test1.cpp中做显示的实例化:
#include "test.h"
template void fun<int> (int);
void test1() { fun(3) ; }
在test2.cpp中做外部模板的说明:
#include "test.h"
extern template void fun<int> (int);
void test1() { fun(3) ; }
这样在test2.o中不会再生成fun<int> (int)
的实例代码。
说明
- 外部模板和外部变量相比,如果不使用外部模板并不会导致任何错误,外部模板更应该说是一种优化编译时间和空间的优化方法。
- 千万不要低估模板实例化的开销, 特别是项目中包含大量模板!
局部和匿名类型作为模板实参
在C++ 98中局部的变量、匿名的类型以及匿名类型的变量都是无法作为模板的实参,当然不能作为模板的实参的还有,匿名的联合体以及枚举类型;
这些看起来都是不必要的限制,在C++ 11中等到了改善(c++11支持了这些用法);见代码:
/*
局部和匿名类型作模板实参
*/
template <typename T>
class X { };
template <typename T>
void TempFun(T t){};
struct A{ } a;
struct {int i;} b; //b为匿名类型变量
typedef struct {int i; } B; //B为匿名类型
void test_template()
{
struct C
{
} c;
X<A> x1; //C++98 通过 C++11通过
X<B> x2; //C++98 错误 C++11通过
X<C> x3; //C++98 错误 C++11通过
TempFun(a); //C++98 通过 C++11通过
TempFun(b); //C++98 错误 C++11通过
TempFun(c); //C++98 错误 C++11通过
}
cuipf
