C++中的类型别名定义: using vs typedef

在 C++ 中,使用复杂类型(如 STL 容器和智能指针)时,类型别名可以简化代码。C++98 使用 typedef 来创建类型别名,而 C++11 引入了更现代的别名声明 (using)。

简单来说,在定义类型别名的时候:using 和 typedef的最主要区别是, using 可以定义 模板类的别名,但是 typedef 不可以。

简单类型别名

对于简单的类型别名,两者用法类似:

typedef int Integer; // 使用 typedef
using Integer = int; // 使用 using

在这种情况下,两者没有显著差异。

复杂类型别名

对于模板类型别名,typedef 的局限性就显现出来了,而 using 提供了更好的解决方案:

使用 typedef 定义模板类型别名
template <typename T>
typedef std::vector<T> Vec_Typedef; // 错误,typedef 不能直接用于模板
Vec_Typedef<int> my_vec;
使用 using 定义模板类型别名
template <typename T>
using Vec_Using = std::vector<T>; // 正确,using 可以直接用于模板
Vec_Using<int> my_vec;

⚠️⚠️⚠️

注意📢:typedef 不可以定义模板类型的别名;但是对于模板类的类型参数已经推演过或者确定 的类,是可以使用 typedef 定义别名,比如:

typedef std::vector<int> Vec_Int;  // 正确,vector 已经指定模板参数类型为 int 。

可读性和可维护性

使用 using 语法定义类型别名时,代码更加直观和可读:

typedef void (*FunctionPointer)(int, int); // 使用 typedef 定义函数指针类型别名

using FunctionPointer = void(*)(int, int); // 使用 using 定义函数指针类型别名

结合 std::enable_if 使用

在模板元编程中,using 使得代码更加简洁。例如,结合 std::enable_if 使用时:

// 使用 typedef
template <typename T>
struct IsInteger {
    typedef typename std::enable_if<std::is_integral<T>::value, T>::type type;
};

// 使用 using
template <typename T>
using IsInteger = typename std::enable_if<std::is_integral<T>::value, T>::type;

作用域🌳

using 和 typedef 是有作用域的::

  • 定义在所有函数和类的外部,则从定义处到文件结尾。
  • 定义在类或者函数内部,则其作用域类似于局部变量的作用范围。
  • 另外⚠️,同一作用域内部不可以 重复声明 相同的类型别名!
void foo(bool useVec) {
    using DTYPE = float;
    // using DTYPE = int;  // 错误!在同一作用域内重复声明名字相同的类型。
    if (useVec) {
        using ArrayType = std::vector<DTYPE>} else {
        using ArrayType = std::array<DTYPE, 10>;  // 正确✅;定义在不同的花括号内,分属不同的作用域,不会引发重定义错误
    }
}

using 与 typedef 的区别和优点

using 相较于 typedef 有许多优点,尤其是在现代 C++ 编程中更为常用。下面我们通过几个具体的例子和原因来展开对比讲解。

1. 模板别名

using 允许我们定义模板别名,而 typedef 则不行。这在处理模板类型时尤为重要,因为模板在泛型编程中广泛使用。

示例:

template <typename T>
using Vec = std::vector<T>; // 使用 using 定义模板别名

使用 typedef 定义模板别名会变得非常麻烦甚至不可能,因为 typedef 不能直接处理模板参数 (但是对于模板参数类型已经推演过或者指定过的模板类是可以使用 typedef 定义别名的 。相反,using 简单直观地允许我们定义模板别名,使代码更简洁明了。

2. 可读性

using 语法更加直观,易于理解和维护。相比之下,typedef 在某些复杂的类型声明中可读性较差。

示例:

using FunctionPointer = void(*)(int, int); // 简单明了的函数指针别名

相同的类型别名如果使用 typedef 来定义,看起来会稍显繁琐:

typedef void(*FunctionPointer)(int, int); // 使用 typedef 定义函数指针别名

可以看出,using 语法更加接近自然语言描述,直观易懂。

3. 模板元编程

在复杂的模板元编程中,using 可以显著减少代码的复杂性,使代码更易读。模板元编程涉及到很多模板参数和类型推导,使用 using 可以更清晰地表达类型关系。

示例:

template <typename T>
using IsInteger = typename std::enable_if<std::is_integral<T>::value, T>::type;

这段代码使用 using 定义了一个模板别名 IsInteger,用于启用整数类型。相比之下,使用 typedef 来实现相同的功能会显得非常复杂,难以理解:

template <typename T>
struct IsInteger {
    typedef typename std::enable_if<std::is_integral<T>::value, T>::type type;
};

using 使得模板元编程中的类型定义变得更加简洁明了,从而提高代码的可读性和可维护性。

using 可以完全取代 typedef 吗?

using 可以在大多数情况下取代 typedef,特别是在现代 C++ 编程中。然而,typedef 仍有一些特定的用例,在这些用例中,typedef 更为合适。

typedef 可以用来定义匿名联合体或结构体,这在某些特定情况下是必要的。

示例:

typedef struct {
    int x;
    int y;
} Point;

使用 using 无法直接定义匿名联合体或结构体。

虽然 using 在大多数情况下可以取代 typedef,并且在现代 C++ 编程中有许多优点,但 typedef 在定义匿名类型和维护旧代码方面仍有其不可替代的作用。因此,推荐在新代码和现代 C++ 项目中尽量使用 using,但在需要定义匿名类型或兼容旧代码时仍可以使用 typedef

总结

typedef 不支持模板化,但别名声明(using)支持。使用别名模板可以避免使用 ::type 后缀和在模板中频繁使用 typename 前缀来引用 typedef。C++14 为所有 C++11 类型特性转换提供了别名模板的支持。

  • 22
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值