一.模板的右尖括号
在C++98/03的泛型编程中,模板实例化有一个很繁琐的地方,就是连续两个右尖括号(>>)会被编译解释成右移操作符,而不是模板参数表的形式。即
<span style="font-size:14px;">template <typename T>
struct Foo
{
typedef T type;
};
template <typename T>
class A
{
// ....
};
int main(){
Foo<A<int>>::type xx;//编译出错
return 0;
}</span>
正确的写法是写成Foo<A<int> >xx。
在C++的成对括号中,只有右尖括号连续写两个会出现这二义性。当static_cast,reinterpret_cast所需转换的类型为模板时,用起来就很麻烦。在C++11中,这种限制被取消了。在C++11标准中,要求编译器对模板的右尖括号做单独处理,使编译器能够正确判断出">>"是一个右移操作符还是模板参数表的结束标记。
template <int N>
struct Foo
{
//...
};
int main(){
Foo<100 >> 2> xx;
return 0;
}
上面的例子中:
1).C++98/03的编译器是没有问题的
2).C++11则会出现错误。解决方法:Foo< (100 >> 2) > xx;
二.模板的别名(using 的用法)
我们知道,typedef可以重定义一个类型的别名,原有类型的一个新的名字,如typedef int Integer;
当我们要定义一个固定以std::string为key的map,我们就需要将其写成如下的模板型式。
template <typename Val>
struct str_map
{
typed std::map<std::string, Val> type;
};
str_map<int>::type ma;
需要加一个繁琐的str_map外敷类,这在我们使用泛型代码时就很麻烦。
现在C++11出现可以重定义一个模板的语法。
template <typename Val>
using str_map = std::map<std::string, Val>;
str_map<int> map1;
使用新的using别名语法定义了std::map的模板别名str_map_t。这相比于使用typedef,是不是简洁了很多呢。
事实上,using包含了typedef的全部功能:
1).对普通类型的重定义(两者等价):
typedef unsigned int unit_t;
using unit_t = unsigned int;
很明显,C++11的using别名语法比typedef清晰,简单。因为typedef的别名语法本质上类似一种解方法的思路。而using语法通过赋值来定义别名,和我们平时思考方式一致。
2).对模板的定义
template <typename T>
struct fun_t
{
typedef void (*type)(T, T);
};
fun_t<int>::type xx_1;
template <typename T>
using func_t = void(*)(T, T);
func_t<int> xx_2;
使用using只是原有的基础上加上template参数列表就可,而不需要像typedef使用繁琐的外敷模板。
三.函数模板的默认模板参数
1.
在C++98/03中,类模板可以有默认参数,而函数模板不支持默认参数。
//OK
template <typename T, typename U =int, U N = 0>
struct Foo
{
//...
};
//error
template <typename T = int>
void func()
{
//...
};
在C++11中,解除了这个限制。可以直接调用。如:
int main(){
func();
return 0;
}
在函数模板的调用中,如果所有模板参数都有默认参数时,就可以像普通函数一样进行调用。
而在类模板中,哪怕所有参数都有默认参数,在使用时也必须在模板名后跟随"<>"来实例化
2.
函数模板的默认模板参数在使用规则上和其他的默认参数也有一些不同,它就没有写在参数表最后的限制。因此,当默认模板参数和模板参数自动推导结合起来使用时,就非常灵活。
template <typename R = int, typename U>
R fun(U val)
{
val
}
int main(){
fun(123);
return 0;
}
易错点:当默认模板参数和模板参数自动推导同时使用时,若函数模板无法自动推导出参数类型时,则编译器将使用默认模板参数;否则使用自动推导出的参数。
template <typename T>
struct identity
{
typedef T type;
}
template <typename T = int>
void func(typename identity<T>::type val, T = 0 )
{
//...
}
int main(){
func(123);
func(123, 123.0);
return 0;
}
func(123)中,默认类型起作用,val为int。
func(123, 123.0),由于第二个参数是double类型,模板参数T将优先被推导为double,因此,val为double。