在C++中,可以创建用作类型名称替代的同义词。这是通过创建 typedef 声明来实现的。这在多种情况下很有用,例如为类型创建更短或更有意义的名称,或者为函数指针命名。然而,typedef声明不能与模板一起使用来创建模板类型别名。例如,std::vector<T> 不是一种类型(std::vector<int> 是一种类型),而是当类型占位符T被替换为实际类型时,可以创建的所有类型的一种家族。在C++11中,类型别名是另一个已声明类型的名称,而别名模板是另一个已声明模板的名称。这两种类型的别名都是通过新的using语法引入的。
如何使用
使用形式 using identifier = type-id 来创建类型别名,如下例所示:
using byte = unsigned char; using byte_ptr = unsigned char *; using array_t = int[10]; using fn = void(byte, double); void func(byte b, double d) { /*...*/ } byte b{42}; byte_ptr pb = new byte[10] {0}; array_t a{0,1,2,3,4,5,6,7,8,9}; fn* f = func;
使用以下形式创建别名模板:template<template-params-list> identifier = type-id,如下例所示:
template <class T> class custom_allocator { /* ... */ }; template <typename T> using vec_t = std::vector<T, custom_allocator<T>>; vec_t<int> vi; vec_t<std::string> vs;
为了保持一致性和可读性,你应该遵循以下做法:
- 在创建别名时,不要混合使用 `typedef` 和 `using` 声明。
- 更倾向于使用 `using` 语法来创建函数指针类型的名称。
工作原理
`typedef` 声明引入了一个类型的同义词(换句话说,就是一个别名)。它不会引入另一种类型(如 `class`、`struct`、`union` 或 `enum` 声明那样)。通过 `typedef` 声明引入的类型名称遵循与标识符名称相同的隐藏规则。它们也可以被重新声明,但只能用来引用相同的类型(因此,在一个翻译单元中,你可以有多个有效的 `typedef` 声明引入相同的类型名称同义词,只要它们是相同类型的同义词)。以下是一些典型的 `typedef` 声明示例:
typedef unsigned char byte; typedef unsigned char * byte_ptr; typedef int array_t[10]; typedef void(*fn)(byte, double); template<typename T> class foo { typedef T value_type; }; typedef std::vector<int> vint_t;
类型别名声明等同于 `typedef` 声明。它可以出现在块作用域、类作用域或命名空间作用域中。根据C++11第7.1.3.2段:
然而,在为数组类型和函数指针类型创建别名时,别名声明更具可读性,并且更清楚地表明了被别名的实际类型。在“如何做”部分的示例中,很容易理解 `array_t` 是一个包含10个整数的数组类型的名称,而 `fn` 是一个函数类型的名称,该函数接受两个参数,类型分别为 `byte` 和 `double`,并返回 `void`。这也与声明 `std::function` 对象的语法一致(例如,std::function<void(byte, double)> f
)。需要注意以下几点:
- 别名模板不能部分或显式特化。
- 当推导模板参数时,模板参数推导永远不会推导出别名模板。
- 特化别名模板时产生的类型不允许直接或间接使用其自身的类型。
新语法的驱动目的是定义别名模板。这些模板在特化时,等同于将别名模板的模板参数替换到类型标识中的模板参数后的结果。
本博客文章除特别声明,全部都是原创!原创文章版权归过往记忆大数据(过往记忆)所有,未经许可不得转载。
本文链接: 【《现代C++编程指南》:创建类型别名和别名模板】(https://www.iteblog.com/archives/10230.html)