類型別名、別名模板 (C++11 起)
來自 cppreference.com
類型別名是引用先前定義的型別的名稱(類似於 typedef
)。
別名模板是引用一族型別的名稱。
目錄 |
[編輯] 語法
別名宣告是具有以下語法的宣告
using identifier attr (可選) = type-id ; |
(1) | ||||||||
template < template-parameter-list >
|
(2) | ||||||||
template < template-parameter-list > requires constraint
|
(3) | (C++20 起) | |||||||
屬性 | - | 任意數量的屬性的可選序列 |
識別符號 | - | 此宣告引入的名稱,它成為型別名稱 (1) 或模板名稱 (2) |
模板引數列表 | - | 模板引數列表,如模板宣告中所示 |
約束 | - | 一個約束表示式,它限制了此別名模板接受的模板引數 |
型別標識 | - | 抽象宣告符或任何其他有效的 type-id(可能引入新型別,如type-id中指出)。type-id 不能直接或間接引用 identifier。請注意,識別符號的宣告點位於 type-id 之後的Semicolon。 |
[編輯] 解釋
1) 類型別名宣告引入了一個名稱,該名稱可以用作 type-id 所表示型別的同義詞。它不引入新型別,也不能改變現有型別名稱的含義。類型別名宣告和 typedef 宣告之間沒有區別。此宣告可以出現在塊作用域、類作用域或名稱空間作用域中。
2) 別名模板是一個模板,當其特化時,它等效於將別名模板的模板引數替換為 type-id 中的模板引數的結果。
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-id時,後續替換適用於該template-id
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 起) |
[編輯] 注意
功能測試宏 | 值 | 標準 | 特性 |
---|---|---|---|
__cpp_alias_templates |
200704L |
(C++11) | 別名模板 |
[編輯] 關鍵詞
[編輯] 示例
執行此程式碼
#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`
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
CWG 1558 | C++11 | 別名特化中未使用的引數 是否參與替換未指定 |
替換 已執行 |
[編輯] 另請參閱
typedef 宣告
|
為型別建立同義詞 |
命名空間別名 | 建立現有名稱空間的別名 |