Namespaces
Variants

Type alias, alias template (since C++11)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

类型别名是指向先前已定义类型的名称(类似于 typedef )。

别名模板是一个指代一系列类型的名称。

目录

语法

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

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

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

(2)
template < 模板形参列表 > requires 约束

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

(3) (自 C++20 起)
attr - 可选的任意数量 属性 序列
identifier - 此声明引入的名称,将成为类型名 (1) 或模板名 (2)
template-parameter-list - 模板形参列表 ,与 模板声明 中相同
constraint - 约束表达式 ,用于限制此别名模板接受的模板形参
type-id - 抽象声明符或任何其他有效的 类型标识 (可能引入新类型,如 类型标识 中所述)。该 type-id 不能直接或间接引用 identifier 。注意标识符的 声明点 位于 type-id 后的分号处。

说明

1) 类型别名声明引入一个名称,该名称可作为 type-id 所指代类型的同义词。它不会引入新类型,也不能改变现有类型名称的含义。类型别名声明与 typedef 声明没有区别。此声明可以出现在块作用域、类作用域或命名空间作用域中。
2) 别名模板是一种模板,当其特化时,等价于将别名模板的模板实参替换到 类型标识 中的模板形参所得到的结果。
template<class T>
struct Alloc {};
template<class T>
using Vec = vector<T, Alloc<T>>; // type-id is vector<T, Alloc<T>>
Vec<int> v; // Vec<int> is the same as vector<int, Alloc<int>>

当特化别名模板的结果是一个依赖的 模板标识 时,后续的替换会应用于该模板标识:

template<typename...>
using void_t = void;
template<typename T>
void_t<typename T::foo> f();
f<int>(); // error, int does not have a nested type foo

特化别名模板所产生的类型不允许直接或间接使用其自身类型:

template<class T>
struct A;
template<class T>
using B = typename A<T>::U; // type-id is A<T>::U
template<class T>
struct A { typedef B<T> U; };
B<short> b; // error: B<short> uses its own type via A<short>::U

在推导模板模板参数时, 模板实参推导 永远不会推导出别名模板。

无法对别名模板进行 部分特化 显式特化

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

出现在别名模板声明中的 lambda表达式 类型在不同模板实例化中是不同的,即使该lambda表达式不依赖模板参数。

template<class T>
using A = decltype([] {}); // A<int> 和 A<char> 引用不同的闭包类型
(since C++20)

注释

特性测试宏 标准 特性
__cpp_alias_templates 200704L (C++11) 别名模板

关键词

using

示例

#include <iostream>
#include <string>
#include <type_traits>
#include <typeinfo>
// 类型别名,等同于
// 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 ContainerT>
void info(const ContainerT& c)
{
    typename ContainerT::value_type T;
    std::cout << "ContainerT is `" << typeid(decltype(c)).name() << "`\n"
                 "value_type is `" << typeid(T).name() << "`\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) { return 1; }
struct S { virtual ~S() {} };
int main()
{
    Container<int> c;
    info(c); // 在此函数中 Container::value_type 将为 int
//  fpoly_only(c); // 错误:enable_if 禁止此调用
    S s;
    fpoly_only(s); // 正确:enable_if 允许此调用
}

可能的输出:

ContainerT is `struct Container<int>`
value_type is `int`

缺陷报告

下列行为变更缺陷报告被追溯应用于先前发布的C++标准。

缺陷报告 适用标准 发布时行为 正确行为
CWG 1558 C++11 未说明别名特化中未使用的参数
是否参与替换
执行
替换

另请参阅

typedef declaration 为类型创建同义词
namespace alias 创建现有命名空间的别名