转向现代C++——优先选用别名声明,而非 typedef

文章目录

优先选用别名声明,而非 typedef

在 C++11 之前,我们只有 typedef 这一种方式来为复杂的类型创建别名。C++11 引入了别名声明,即 using 关键字。别名声明在许多方面看似会更优于 typedef。

🔊在 Modern C++ 中,**除非你在写兼容 C++98 的老古董代码,否则一律推荐使用 using

语法直观性与可读性

对于基础类型或简单的结构体,两者区别不大。但在处理函数指针数组指针等复杂类型时,using 的语法明显更加直观。

cpp 复制代码
// ==================== 传统 typedef 语法 ====================
// typedef 的新名称被"埋"在类型的中间,可读性较差
typedef void (*FP)(int, const std::string&); 

// ==================== Modern C++ using 语法 ====================
// using 的结构非常清晰:新名称 = 实际类型,符合人类从左到右的阅读习惯
using FP = void (*)(int, const std::string&);

// 示例用法(两者一致)
void myFunction(int a, const std::string& b) {}
FP ptr = myFunction;

对模板的支持

:::info

这是优先选用 using 的决定性原因

:::

当我们想为一个模板类型创建别名(即"模板别名",化名别名模板)时,using 可以直接支持,而typedef` 必须套娃一个外部结构体,极其繁琐。

假设我们想定义一个自定义分配器的 std::list 别名:

cpp 复制代码
// 编译错误!typedef 不支持直接模板化
template<typename T>
typedef std::list<T, MyAlloc<T>> MyList;

为了实现这个目的,在 C++98 中,你必须把 typedef 嵌套在一个模板结构体(struct)里:

cpp 复制代码
template<typename T>
struct MyList {
    typedef std::list<T, MyAlloc<T>> type; // 嵌套在里面
};

// 使用时的代码:
MyList<int>::type myIntList; // 每次用都要加后缀 ::type

使用别名声明,你可以直接像定义普通模板一样定义它:

cpp 复制代码
template<typename T>
using MyList = std::list<T, MyAlloc<T>>; // 直接、自然

// 使用时的代码:
MyList<int> myIntList; // 清爽,无需 ::type

避免依赖别名时的"二次伤害"

如果你在一个模板类内部去使用上面定义的模板别名,typedef 的弊端会被进一步放大------它强迫你写 typename` 关键字。

cpp 复制代码
template<typename T>
class Widget {
private:
    // 必须写 typename,因为编译器不知道 MyList<T>::type 是一个类型还是一个静态成员变量
    typename MyList<T>::type list; 
};
cpp 复制代码
template<typename T>
class Widget {
private:
    // 不需要 typename!
    MyList<T> list; 
};

🤔**为什么 using 不需要 ****typename**`**?**

:::info

因为 MyList 是一个别名模板(alias template) ,C++ 标准明确规定:当编译器看到 MyList` 时,它明确知道这是一个类型

而 MyList::type 是一个从属依赖名称(dependent type,编译器在实例化之前无法确定 type 究竟是一个类型,还是一个恰好叫 type 的静态数据成员(例如某些特化版本里它可能不是类型),所以必须强制加 `typename 明确告知编译器。

:::

标准库的现身说法:<type_traits> 的演进

C++11 引入了 <type_traits> 用于元编程。早期这些工具都是用 `typedef 配合结构体实现的。

比如你想去除一个类型的引用,或者获取其常量版本:

cpp 复制代码
typename std::remove_reference<T>::type  // 繁琐
typename std::add_const<T>::type        // 繁琐

这种语法太啰嗦,C++14 利用 using 为所有的 traits 重新提供了别名模板版本(即带有 _t` 后缀的版本):

cpp 复制代码
std::remove_reference_t<T>   //简洁
std::add_const_t<T>          //简洁

标准库底层的实现原理恰恰就是typedef 向别名声明的转换

cpp 复制代码
template <typename T>
using remove_reference_t = typename remove_reference<T>::type;
相关推荐
nvvas2 小时前
Java 入门(四):数组——数据的集合管理
java·开发语言
钓鱼的肝2 小时前
csp-j-s总结(2)
c++·经验分享·笔记·算法·青少年编程
重生的黑客2 小时前
Qt 常用控件精讲(1):QWidget 核心属性全解 —— 从 geometry 到 qrc 与 QSS
c++·qt·qwidget·qss·常用控件
Hespethorn2 小时前
取 `X-Forwarded-For` 首段做频控 key,等于把限流开关交给了调用方
c++
米糕闯编程2 小时前
鱼香ros2(七)功能包组织C++节点
c++·ros2·cmakelists
Y3815326623 小时前
SERP 数据清洗实战:字段标准化、日期解析与去重键
开发语言·数据库·python·python数据库
汉克老师3 小时前
GESP2026年9月认证C++四级( 第三部分编程题(1、新汉诺塔))精讲
c++·gesp·小学生·学c++编程
君顾13 小时前
本地城市低空经济管理系统定制:城市级低空运营平台架构与落地实战
java·开发语言·飞手
多多鼠4 小时前
System Prompt 的“版本漂移”问题:从变更管理到 A/B 测试体系
开发语言·网络·人工智能·python·langchain
唠玖馆4 小时前
智能指针详解
c++