大家都知道,在c++中可以通过typedef重定义一个类型:
typedef unsigned int uint_t;
被重定义的类型名叫“typedef-name”。他并不是一个新的类型,仅仅只是原有的类型取了一个新的名字;因此下列函数重载是不合法的:
void fun(unsigned int);
void fun(uint_t);
使用typedef重定义类型是很方便的,但它也有一些限制,比如,无法重定义一个模板。例如,我们想要一个固定以std::string 为 key 的 map,他可以映射到 int 或另一个 std::string。然而这个简单的需求仅通过typedef却很难办到。
template<typename T>
struct map_t{
typedef std::map<std::string, T> type;
};
map_t<int>::type map_int_t;
一个虽然简单但却略显烦琐的map_t外敷类是必要的。这明显让我们在复用某些反省代码时非常难受。
c++11出现了可以重定义一个模板的语法:
template<typename T>
using str_map_t = std::map<std::string, T>;
std_map_t<int> map_int;
这里使用新的using别名语法定义了std::map 的模板别名 str_map_t 。比起前面使用外敷模板加typedef 构建的 map_t,它就像是一个新的 map 类模板,简洁了许多。实际上,using的别名语法覆盖了typedef的全部功能。例如:
typedef unsigned int uint_t;
using uint_t = unsigned int;
这两种使用方法是等价的,唯一不同的是定义语法。
2、函数模板的默认模板参数
在c++98/03中,类模板可以有默认的模板参数,如下:
template <typename T, typename U = int, U N = 0>
struct Foo{
//...
};
但是却不支持函数的默认模板参数
template <typename T = int>//error int c++98/03: default template arguments
void fun(coid){
//...
}
这一限制在c++11被解除了。上面的fun 函数可以在 c++11 中直接使用:
int main(){
fun();
return 0;
}
函数模板的默认模板参数在使用规则上和其他的默认参数也有一些不同,它没有必须写在参数表最后的限制。当默认模板参数和模板参数自动推导结合起来时,书写显得非常灵活:
template <typename R = int, typename U>
R fun(U val){
//...
}
int main(){
fun(123);
return 0;
}
但是需要注意的是,在调用函数模板时,若显示指定模板的参数,由于参数填充顺序是从左往右的,因此,像下面这样调用:
fun<long>(123); //fun的返回类型是long
另外,当默认模板参数和模板自动推导同时使用时,若函数模板无法自动推导出参数类型,则编译器将使用默认模板参数;否则将使用自动推导出的参数类型。
template <typename T>
struct identity{
typedef T type;
};
template <typename T = int>
void fun(typename identity<int>::type val, T = 0){
//....
}
int main(){
fun(123); //T -> int
fun(123, 123.0); //T -> double
return 0;
}