在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); // error 不合法的重载
上面的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; // using替代typedef
typedef std::map<std::string, int> map_t;
using map_t = std::map < std::string, int >; // using替代typedef
可以看到在对普通类型的别名定义上,两种方法的使用基本等效,唯一不同的仅仅是定义的语法,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仅仅是定义一个别名,不会创造新类型。