C++11之模板别名&函数模板的默认模板参数

原创 2017年01月03日 15:27:50

模板别名

在C++98/03里,我们可以通过typedef 关键字定义一个类型的别名,比如 typedef unsigned int uint_t;在这里我们定义了unsigned int类型的别名和uint_t,在以后需要使用unsigned int的时候我们都可以用uint_t替换,但是uint_t仅仅是作为unsigned int的一个别名,如下的定义是不合法的:

typedef unsigned int uint_t;
void  func(unsigned int);
void  func(uint_t);
上面的func函数是一个不合法的函数重载,虽然使用typedef定义一个类型的别名很方便,但是typedef在使用上存在一些限制,比如说typedef无法重定义一个模板的别名。

考虑下面例子,我们在实际编程中经常使用到STL中的MAP,我们MAP的string类型的数据作为MAP的key,我们想根据STRING类型的KEY映射为一个String,int,long等类型的数据.

typedef std::map<std::string, int> map_t;
//...
typedef std::map < std::string, std::string > map_str;
//...
如果需要映射成10中类型的数据,我们就需要利用typedef定义10个具体类型的别名,但是考虑到MAP的key值始终是变的,我们是否像下面一样可以用typedef+模板来定义一个别名呢

template <typename T>
typedef std::map<std::string, T> map;
map<int>  map_i;
map<std::string>  map_str;
遗憾的是上述的定义不能通过编译,也就是C++ 98/03并不支持这样的操作,而通常是通过一个包裹类的方式来实现上述的需求:

template <typename T>
struct alias_map
{
	typedef std::map<std::string, T> map;
};

alias_map<int>::map map_t;
alias_map<int>::map map_str;

通过包裹类的方法虽然可以实现上述的需求,但是一看代码就觉得,这个代码可读性差,不就是定义一个变量吗?还需要整一个包裹类来封装下,增加代码里不说,看着都烦,小幸运的是C++11终于让你可以不用通过上述这种臃肿的方式来实现这个需求了。C++11中,新增了一个特性就是可以通过使用using来为一个模板定义别名,比如说上述的需求,使用C++11就可以这样实现:

template <typename T>
using alias_map = std::map < std::string, T > ;

alias_map<int>  map_t;
alias_map<std::string> map_str;
系不系看着舒服很多啊,顿时神清气爽,在C++11中,允许使用using关键字为一个模板来定义别名,实际上using包含了typedef的所有功能,来看下使用using关键字和typedef关键字定义普通类型别名的用法。

typedef unsigned int uint_t;
using uint_t = unsigned int;

typedef std::map<std::string, int> map_t;
using map_t = std::map < std::string, int > ;
可以看到在对普通类型的别名定义上,两种方法的使用基本等效,唯一不同的仅仅是定义的语法,using使用起来就像是赋值,但是在定义函数函数指针的时候,using看起来可读性要稍微好一点,比如:

typedef void(*func)(int, int);
using func = void(*)(int, int);
可能突然看起来使用using的方式来定义一个函数指针有点怪,但是习惯了之后会发现使用using这种赋值的方式更适用开发人员的思考方式。下面再显示一个通过typedef和using方式分别来定义一个函数模板的例子:

template<typename T>
struct FuncSt
{
	typedef void(*func)(T, T);
};

FuncSt<int>::func func_typedef;


template<typename T>
using func_using = void(*func)(T, T);
func_using<int> func_using;
可以看到通过using定义模板别名的语法,仅仅是在普通类型别名语法基础上增加了template参数列表,通过using可以轻松的创建一个模板的别名,而不需要像C++98/03那样增加一个包裹类。但是需要额外注意的是使用using或者typedef仅仅是定义一个别名,不会创造新类型。


函数的默认模板参数

在C++98/03里,类模板是支持默认的模板参数的,比如:

template<class T, class U = int, U n= 0>
struct Foo
{
	//
};
但是在C++98/03中确实不能支持函数模板的默认模板参数:

template <typename T = int> //error in C++98/03 default template arguments
void func(void)
{
//...
}
现在这个限制在C++11中已经解除,上述的定义在C++11中可以直接使用了。在函数模板中当所有模板参数都有默认参数时,函数的调用就如同普通的函数调用,但是对于类末班而言,哪怕所有模板参数都有默认构造函数在使用时还是必须在模板名后跟随<>来实例化。

C++11中函数的默认模板参数在使用规则上和其他的默认参数也有一些区别,普通函数的默认参数必须写在参数列表的最后,而函数的模板参数就没有这个限制,因此当使用默认模板参数和模板参数自动推导时就显示十分灵活,可以指定函数中的一部分参数是默认参数,另一部分采用自动推导。比如:

template <typename R = int, typename U>
R func(U val)
{
	//...
}

int _tmain(int argc, _TCHAR* argv[])
{
	func(123);
	return 0;
}
但是如果在使用函数模板时如果显示指定模板的参数,由于模板参数的填充顺序是自左向右的,因此像下面这样的调用返回的类型是long类型:

func<long>(123); //func返回类型是填充类型long

这个细节虽然简单,但是在多个默认模板参数和多个模板参数自动推导穿插使用时会容易被忽略掉,造成使用上的一些意外,建议在使用的时候尽量还是价格默认模板参数写在模板参数的末尾;另外当默认模板参数和自动参数推导同时使用时,若函数模板无法推导出参数类型时,编译器将使用默认模板参数,否则将使用自动推导的参数类型。这个跟函数的默认参数使用规则是一致的,比较好理解。


模板别名以及默认模板参数是在泛型编程中的一些小细节,是C++11对C++98/03一些细节上的提升,因此介绍的篇幅不多,主要是在使用的时候若可以的话可以通过这些小技巧增加代码可读性,减少代码冗余。

版权声明:本文为博主原创文章,未经博主允许不得转载。

模板类的默认模板参数、模板函数不支持默认模板参数

在这个学期开始学习使用模板,当然模板早在大一期间就用到了一些,但是都是作为练习语法用的。这个学期中使用了大量的模板来进行类的设计与实现,具体的来说应该几乎是这个学期的所有的C++代码都是用的模板实现的...
  • ZLhy_
  • ZLhy_
  • 2012年12月26日 01:37
  • 7396

C++之:模板元编程(三) 默认模板参数

一、类模板的默认模板参数原则  1、可以为类模板的类型形参提供默认值,但不能为函数模板的类型形参提供默认值。函数模板和类模板都可以为模板的非类型形参提供默认值。  2、类模板的类型形参默认值形式为:t...

《C++高级编程》--类模板三种类模板参数

实际上有三种类型模板参数:类型模板参数、无类型模板参数和模板模板参数(以模板作为模板的参数)。 1、类型模板参数 类型模板参数是我们使用模板的主要目的。我们可以定义多个类型模板参数: templ...

深入浅出C++11(6)-- 外部模板

为什么需要外部模板 先来看一个例子: //fun.h template void fun(T t){ } //use1.cpp void test1(){ fun(1); } //use2.c...

C++11(15): 模板与泛型编程

面向对象编程和泛型编程都能处理在编写程序时不知道类型的情况。不同之处:OOP能处理类型在程序运行之前都未知的情况;而泛型编程中,在编译时就能获知类型了 模板参数类别不能为空。 模板参数表示在类或函...

c++11 条款1:理解模板类型推导

前言 c++98有单独一套类型推导规则:适用用函数模板。c++11修改了这套规则并且增加了两个,一个是auto,一个是decltype。c++14扩展了auto和decltype使用的场景。随着类型推...

关于c++中类型定义typedef和类模板能否共用问题

#include #include using namespace std; template class A { typedef deque cont; protected: cont ...

C++模板 别名 typedef 替代方案

by  [csdn]@plainsong—— template struct Func { typedef T (*result)(T n); }; 用的时候:...

C++11 理解 (十五) 之 模板的别名

在进入这个主题之前,各位应该先弄清楚“模板”和“类型”本质上的不同。class template (类型模板,是模板)是用来产生 template class (模板类型,是类型)。 在标准 C++...

C++11变长模板解析(深入理解C++11)

参考自:深入理解C++11 变长模版:       变长函数和变长的模版参数        变长函数:        double sum(int n, ...)//求n个do...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++11之模板别名&函数模板的默认模板参数
举报原因:
原因补充:

(最多只允许输入30个字)