类型别名,别名模板 (自 C++11 起)
来自 cppreference.com
类型别名是引用先前定义的类型的名称(类似于 typedef
)。
别名模板是引用类型族的名称。
内容 |
[编辑] 语法
别名声明是具有以下语法的 声明
using 标识符 attr (可选) = 类型标识 ; |
(1) | ||||||||
template < 模板参数列表 >
|
(2) | ||||||||
template < 模板参数列表 > requires 约束
|
(3) | (自 C++20 起) | |||||||
attr | - | 任何数量的 属性 的可选序列 |
标识符 | - | 此声明引入的名称,它将成为类型名称 (1) 或模板名称 (2) |
模板参数列表 | - | 模板参数列表,如在 模板声明 中 |
约束 | - | 一个 约束表达式,它限制此别名模板接受的模板参数 |
类型标识 | - | 抽象声明符或任何其他有效的 类型标识(它可能引入新的类型,如在 类型标识 中所述)。类型标识 不能直接或间接引用 标识符。请注意,标识符 的 声明点 在 类型标识 后面的分号处。 |
[编辑] 说明
1) 类型别名声明引入一个名称,该名称可以作为 类型标识 所表示类型的同义词使用。它不引入新的类型,也不能改变现有类型名称的含义。类型别名声明与 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> and A<char> refer to different closure types |
(自 C++20 起) |
[edit] 说明
特性测试宏 | 值 | Std | 特性 |
---|---|---|---|
__cpp_alias_templates |
200704L | (C++11) | 别名模板 |
[edit] 关键字
[edit] 示例
运行此代码
#include <iostream> #include <string> #include <type_traits> #include <typeinfo> // type alias, identical to // typedef std::ios_base::fmtflags flags; using flags = std::ios_base::fmtflags; // the name 'flags' now denotes a type: flags fl = std::ios_base::dec; // type alias, identical to // typedef void (*func)(int, int); using func = void (*) (int, int); // the name 'func' now denotes a pointer to function: void example(int, int) {} func f = example; // alias template template<class T> using ptr = T*; // the name 'ptr<T>' is now an alias for pointer to T ptr<int> x; // type alias used to hide a template parameter template<class CharT> using mystring = std::basic_string<CharT, std::char_traits<CharT>>; mystring<char> str; // type alias can introduce a member typedef name template<typename T> struct Container { using value_type = T; }; // which can be used in generic programming 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"; } // type alias used to simplify the syntax of 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 will be int in this function // fpoly_only(c); // error: enable_if prohibits this S s; fpoly_only(s); // okay: enable_if allows this }
可能的输出
ContainerT is `struct Container<int>` value_type is `int`
[edit] 缺陷报告
以下更改行为的缺陷报告被追溯应用于先前发布的 C++ 标准。
DR | 应用于 | 发布的行为 | 正确行为 |
---|---|---|---|
CWG 1558 | C++11 | 别名特化中未使用的参数是否参与替换没有指定 执行替换 |
替换 被执行 |
[edit] 参见
typedef 声明
|
创建类型的同义词 |
命名空间别名 | 创建现有命名空间的别名 |