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

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

语法

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

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

解释

1) 类型别名声明引入一个名字,可用做 类型标识 所指代的类型的同意词。它不引入新类型,且不能更改既存类型名的含义。类型别名声明和 typedef 声明之间无区别。此声明可出现于块作用域、类作用域或命名空间作用域。

2) 别名模板是一种模板,当其特化时等价于以别名模板的模板实参来替换 类型标识 中的模板形参的结果。

  1. template<class T>
  2. struct Alloc { };
  3. template<class T>
  4. using Vec = vector<T, Alloc<T>>; // 类型标识为 vector<T, Alloc<T>>
  5. Vec<int> v; // Vec<int> 同 vector<int, Alloc<int>>

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




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



(C++14 起)

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

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

在推导模板模板形参时,模板实参推导始终不推导别名模板。
不可能部分特化显式特化别名模板。

与任何模板声明相似,别名模版仅可声明于类作用域或命名空间作用域。


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




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



(C++20 起)

示例

运行此代码

  1. #include <string>
  2. #include <ios>
  3. #include <type_traits>
  4.  
  5. // 类型别名,等同于
  6. // typedef std::ios_base::fmtflags flags;
  7. using flags = std::ios_base::fmtflags;
  8. // 名字 'flags' 现在指代类型:
  9. flags fl = std::ios_base::dec;
  10.  
  11. // 类型别名,等同于
  12. // typedef void (*func)(int, int);
  13. using func = void (*) (int, int);
  14. // 名字 'func' 现在指代函数指针:
  15. void example(int, int) {}
  16. func f = example;
  17.  
  18. // 别名模板
  19. template<class T>
  20. using ptr = T*;
  21. // 名字 'ptr<T>' 现在是指向 T 的指针的别名
  22. ptr<int> x;
  23.  
  24. // 用于隐藏模板形参的别名模版
  25. template<class CharT>
  26. using mystring = std::basic_string<CharT, std::char_traits<CharT>>;
  27. mystring<char> str;
  28.  
  29. // 别名模板可引入成员 typedef 名
  30. template<typename T>
  31. struct Container { using value_type = T; };
  32. // 可用于泛型编程
  33. template<typename ContainerType>
  34. void g(const ContainerType& c) { typename ContainerType::value_type n; }
  35.  
  36. // 用于简化 std::enable_if 语法的类型别名
  37. template<typename T>
  38. using Invoke = typename T::type;
  39. template<typename Condition>
  40. using EnableIf = Invoke<std::enable_if<Condition::value>>;
  41. template<typename T, typename = EnableIf<std::is_polymorphic<T>>>
  42. int fpoly_only(T t) { return 1; }
  43.  
  44. struct S { virtual ~S() {} };
  45.  
  46. int main()
  47. {
  48. Container<int> c;
  49. g(c); // Container::value_type 将在此函数为 int
  50. // fpoly_only(c); // 错误:enable_if 禁止它
  51. S s;
  52. fpoly_only(s); // OK:enable_if 允许它
  53. }

缺陷报告

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

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