类型别名,别名模板 (C++11 起)

来自cppreference.com
< cpp‎ | language

类型别名是指代【先前定义的类型】的名字(与 typedef 类似)。

别名模版是指代一族类型的名字。

语法

别名声明是具有下列语法的声明

using 标识符 属性(可选) = 类型标识 ; (1)
template < 模板形参列表 >

using 标识符 属性(可选) = 类型标识 ;

(2)
属性(C++11) - 可选的任意数量属性的序列
标识符 - 此声明引入的名字,它成为一个类型名 (1) 或一个模板名 (2)
模板形参列表 - 模板形参列表,同模板声明
类型标识 - 抽象声明符或其他任何合法的 类型标识(可以引入新类型,如 类型标识 中所注明)。类型标识 不能直接或间接涉指 标识符。注意,标识符的声明点处于跟在 类型标识 之后的分号处。

解释

1) 类型别名声明引入一个名字,可用做 类型标识 所指代的类型的同义词。它不引入新类型,且不能更改既存类型名的含义。类型别名声明和 typedef 声明之间没有区别。此类声明可出现于块作用域、类作用域或命名空间作用域。
2) 别名模板是一种模板,当其特化时等价于以别名模板的模板实参来替换 类型标识 中的模板形参的结果。
template<class T>
struct Alloc { };
template<class T>
using Vec = vector<T, Alloc<T>>; // 类型标识为 vector<T, Alloc<T>>
Vec<int> v; // Vec<int> 等同于 vector<int, Alloc<int>>

当特化别名模板的结果是一个待决的模板标识时,对这个模板标识应用后继的替换:

template<typename...>
using void_t = void;
template<typename T>
void_t<typename T::foo> f();
f<int>(); // 错误,int 没有嵌套类型 foo

特化别名模版时所生成的类型不允许直接或间接使用它自己的类型:

template<class T>
struct A;
template<class T>
using B = typename A<T>::U; // 类型标识为 A<T>::U
template<class T>
struct A { typedef B<T> U; };
B<short> b; // 错误:B<short> 通过 A<short>::U 使用其自身类型

在推导模板模板形参时,模板实参推导始终不推导别名模板。

不能部分特化显式特化别名模板。

与任何模板声明相似,别名模版只能在类作用域或命名空间作用域被声明。

出现于别名模版声明中的lambda 表达式的类型在该模板的不同实例化间不同,即使该 lambda 表达式非待决。

template <class T>
using A = decltype([] { }); // A<int> 与 A<char> 指代不同的闭包类型
(C++20 起)

示例

#include <string>
#include <ios>
#include <type_traits>
 
// 类型别名,等同于
// typedef std::ios_base::fmtflags flags;
using flags = std::ios_base::fmtflags;
// 名字 'flags' 现在指代类型:
flags fl = std::ios_base::dec;
 
// 类型别名,等同于
// typedef void (*func)(int, int);
using func = void (*) (int, int);
// 名字 'func' 现在指代函数指针:
void example(int, int) {}
func f = example;
 
// 别名模板
template<class T>
using ptr = T*; 
// 名字 'ptr<T>' 现在是指向 T 的指针的别名
ptr<int> x;
 
// 用于隐藏模板形参的别名模版
template<class CharT>
using mystring = std::basic_string<CharT, std::char_traits<CharT>>;
mystring<char> str;
 
// 别名模板可引入成员 typedef 名
template<typename T>
struct Container { using value_type = T; };
// 可用于泛型编程
template<typename ContainerType>
void g(const ContainerType& c) { typename ContainerType::value_type n; }
 
// 用于简化 std::enable_if 语法的类型别名
template<typename T>
using Invoke = typename T::type;
template<typename Condition>
using EnableIf = Invoke<std::enable_if<Condition::value>>;
template<typename T, typename = EnableIf<std::is_polymorphic<T>>>
int fpoly_only(T t) { return 1; }
 
struct S { virtual ~S() {} };
 
int main() 
{
    Container<int> c;
    g(c); // Container::value_type 将在此函数中是 int
//  fpoly_only(c); // 错误:被 enable_if 禁止
    S s;
    fpoly_only(s); // OK:被 enable_if 允许
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
CWG 1558 C++11 别名模板特化中的未使用实参是否参与替换是未指明的 进行替换

参阅

typedef 声明 为类型创建同义词
命名空间别名 为既存命名空间创建一个别名