具有两种声明别名的方法:
c++
typedef std::unique_ptr<std::unordered_map<std::string, std::string>> UPtrMapSS;
using UPtrMapSS = std::unique_ptr<std::unordered_map<std::string, std::string>>;
别名声明在处理涉及函数指针的类型时比较容易理解:
c++
//FP是一个指向函数的指针的同义词,它指向的函数带有int和const std::string&形参,不返回任何东西
typedef void (*FP)(int, const std::string&); //typedef
//含义同上
using FP = void (*)(int, const std::string&); //别名声明
别名声明可以模板化(被称为别名模板),而typedef不行:
使用别名声明:
c++
template<typename T>
using MyAllocList = std::list<T,MyAlloc<T>>; // MyAllocList<T>是std::list<T,MyAlloc<T>>的同义词
MyAllocList<Widget> lw; // 客户代码
使用typedef需要从头开始:
c++
template<typename T>
struct MyAllocList {
typedef std::list<T, MyAlloc<T>> type;
}; //MyAllocList<T>是std::list<T, MyAlloc<T>>的同义词
MyAllocList<Widget>::type lw; // 客户代码
模板内使用的差异:typename 的必要性
模板内引用嵌套typedef的类型时,必须加typename前缀(因MyAllocList<T>::type是依赖类型 ------ 编译器无法确定特化版本中::type是否为类型):
c++
template<typename T>
class Widget {
private:
// 必须加typename:MyAllocList<T>::type依赖于T,可能被特化为非类型(如数据成员)
typename MyAllocList<T>::type list;
};
// 特化示例:MyAllocList<Wine>::type不是类型,而是数据成员
class Wine {};
template<>
class MyAllocList<Wine> {
private:
enum class WineType { White, Red, Rose };
WineType type; // 此处type是数据成员,非类型别名
};
而别名模板无需typename(编译器明确其结果必为类型,属于非依赖类型):
c++
template<typename T>
class Widget {
private:
MyAllocList<T> list; // 无typename、无::type,简洁且无歧义
};
类型特性(type traits)场景的适配
C++11 的 type traits(如类型转换)基于struct嵌套typedef实现,使用时需::type后缀 + 模板内typename:
c++
// C++11:需::type后缀,模板内还需加typename
std::remove_const<T>::type; // 移除const修饰
std::remove_reference<T>::type; // 移除引用修饰
std::add_lvalue_reference<T>::type; // 添加左值引用
C++14 提供了基于别名声明的简化版本(后缀_t),无需::type和typename;即便仅支持 C++11,也可手动仿写这些别名模板:
c++
// C++14简化版
std::remove_const_t<T>; // 等价于std::remove_const<T>::type
std::remove_reference_t<T>; // 等价于std::remove_reference<T>::type
// C++11手动仿写别名模板(兼容方案)
template <class T>
using remove_const_t = typename std::remove_const<T>::type;
总结
typedef不支持模板化,但别名声明支持。- 别名模板可以让人免写
::type后缀,并且在模板内,对于内嵌typedef的引用经常要求加上typename前缀。