类型别名,别名模版 (C++11 起)
来自cppreference.com
类型别名是指代先前定义的类型的名字(与 typedef 类似)。
别名模版是指代一族类型的名字。
语法
别名声明是具有下列语法的声明:
using 标识符 attr(可选) = 类型标识 ;
|
(1) | ||||||||
template < 模板形参列表 >
|
(2) | ||||||||
attr(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 |
(C++14 起) |
特化别名模版时所生成的类型,不允许直接或间接使用其自身类型:
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++ 标准。
DR | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
CWG 1558 | C++14 | 别名模板特化中的未使用实参是否参与替换是未指明的 | 进行替换 |
参阅
typedef 声明 | 为类型创建同义词 |