C++11 改进了编译器的解析规则,尽可能的将多个“>”解析成模板参数结束符,方便了编写模板的相关代码。
一 模板的右尖括号(“>”)
在C++11之前,下面的这段代码在编译时将会报错,C++11之后,编译器将能够正常编译,代码如下:
template <typename T>
struct Foo{
typedef T type;
};
template <typename T>
class A{
//
};
int main(){
Foo<A<int>>::type t;
return 0;
}
C98编译时,上述代码将会报错Foo<A<int>>这种写法将不被支持。需要写成如下格式:Foo<A<int> >;在C++11之后,这种限制已经被取消,编译器已经能够做出正确判断并进行编译。
二、模板的别名
在C98中,可以使用typedef重定义一个类型,如:
typedef unsigned int uint_t;
在上面的代码中无符号整型类型被重新定义,但并不是新增一种类型,只是给已存在的类型重新定义了一个别名。
如果重新定义一个模板时,使用typedef将会使代码变得复杂,增加了编码的复杂度,如:
template <typename Val>
struct str_map{
typedef std::map<std::string,Val> type;
};
str_map<int> type_map;
上面的代码使用的是C98格式,需要额外增加一个壳,C++11种提供一个新的语法,上面的代码可以写成如下方式:
template <typename Val>
using str_map = std::map<std::string,Val>;
str_map<int> map1;
如上代码所示,C98和C++11实现的功能一样,但是C++11实现代码则更加简洁。
C++11的using语法提供的功能已经涵盖了typedef的所有功能,如在一开始定义的无符号整型的别名也可以这样定义:
using uint_t = unsigned int;
由此可以看出,typedef定义方法和变量声明类似,显示了C++语法的一致性,但是有时又会增加C++代码的阅读复杂度,如在对函数指针进行重定义时:
typedef void (*func_t)(int ,int);
使用using语法时,using紧接着的是标识符,和赋值语法类似,将一个现有的类型赋值给新的类型。和typedef相比,代码更清晰,易于阅读。
using func_t = void (*)(int,int);
下面在来看下如何使用using语法,实现为一个模板定义一个别名。大家可以留言回复使用C98语法如何为一个模板定义一个别名。
/*C++11*/
template <typename T>
using func_t= void (*) (T,T);
func_t<int> xx;
在这里需要注意的是:不管是typedef还是using,都不会新增一个类型,而是对原有类型进行重新定义一个别名。using语法更加强大,编写出的代码更加简洁。
三、函数模板的默认模板参数
在C98中,类模板可以有默认模板参数,函数模板中的默认模板参数是不被支持的,这一限制,在C++11中得到了解除。如下面代码所示:
template <typename R=int,typename U>
R func(U val){
val
}
int main(){
func(123);
return 0;
}
值得注意的是,如果在使用函数模板时显示指定了模板参数的类型,函数的返回值将返回的是指定参数的类型。如:
func<long long>(123);//func的返回值为long long
还有一种使用方式是将函数模板默认参数和模板参数自动推导一起使用,在一起使用时,如果函数模板无法自动推导,将会使用默认模板参数,否则将使用自动推导出的参数类型。如下代码:
template <typeame 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;
}
在上面的代码中,通过identity禁用了val的自动推导,但因为指定了默认参数模板类型,因此,在func(123)中,func的val参数将为int整型,在func(123,123.0)中,第二个参数为浮点行,模板参数T将优先被推导,自动推导生效时,默认模板参数会被直接忽略。
<END>
如果大家有什么意见或者建议,请在下发评论留言。谢谢。