【Effective Modern C++】第三章 转向现代C++:9. 优先选用别名声明,而非typedef

具有两种声明别名的方法:

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),无需::typetypename;即便仅支持 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前缀。

原著在线阅读地址

相关推荐
h_a_o777oah8 分钟前
状态机+划分型 DP :深度解析K-划分问题下 DP 状态的转移逻辑(洛谷P2679 P2331 附C++代码)
c++·算法·动态规划·acm·状态机dp·划分型dp·滚动数组优化
雪度娃娃2 小时前
Asio异步读写——连接的安全回收问题
开发语言·c++·安全·php
不吃土豆的马铃薯2 小时前
Spdlog 进阶:日志基本控制、日志格式控制、异步记录器
linux·服务器·开发语言·前端·c++
liulilittle2 小时前
TCP UCP:基于卡尔曼滤波的BBR增强型拥塞控制算法
linux·网络·c++·tcp/ip·算法·c·通讯
咩咦3 小时前
C++学习笔记26:static 静态成员
c++·学习笔记·static·静态成员变量·静态成员·静态成员函数
秋落风声3 小时前
内存池仿Nginx C++实现
c++·nginx
小白要努力sgy3 小时前
实时通信框架CyberRT
c++·自动驾驶·实时通讯
hansang_IR3 小时前
【记录】loj2967「COCI 2010.03.06」PROGRAM
c++·算法
霍霍的袁5 小时前
【C++初阶】缺省参数(默认参数)详细讲解
开发语言·c++·算法
楼田莉子5 小时前
C++17新特性:optional/variant/any/string_view
c++·后端·学习