佔位符型別說明符 (自 C++11 起)
佔位符型別說明符指定了一個「佔位符型別」,該型別將在稍後被替換,通常是透過初始化式 (initializer) 推導得出。
目錄 |
[編輯] 語法
型別限制 (type-constraint) (可選) auto |
(1) | ||||||||
型別限制 (type-constraint) (可選) decltype(auto) |
(2) | (C++14 起) | |||||||
| type-constraint (型別約束) | - | (自 C++20 起) 一個概念 (concept) 名稱,可選擇是否加上限定符,並可選擇隨後跟隨一個以 <> 包圍的範本引數列表 |
佔位符 auto 可伴隨修飾符,例如 const 或 &,它們會參與型別推導。佔位符 decltype(auto) 必須是所宣告型別的唯一組成部分。(自 C++14 起)
|
若存在 型別限制 (type-constraint),令
若約束運算式無效或回傳 false,則推導失敗。 |
(自 C++20 起) |
[編輯] 說明
佔位符型別說明符可出現在以下上下文中:
參數宣告在下列參數宣告中,所宣告參數的型別可以使用語法 (1)
|
(C++14 起) |
|
(自 C++17 起) |
|
(自 C++20 起) |
[編輯] 函式宣告
佔位符型別可出現在包含後置回傳型別的函式宣告子的宣告說明符中。
| (C++14 起) |
auto f() -> int; // OK: f returns int auto g() { return 0.0; } // OK since C++14: g returns double auto h(); // OK since C++14: h’s return type will be deduced when it is defined
[編輯] 變數宣告
使用佔位符型別宣告的變數,其型別從其初始化式推導得出。此用法允許用於變數的初始化宣告中。
佔位符型別僅能作為宣告說明符序列中的其中一個宣告說明符,或作為後置回傳型別中指定替換該宣告說明符之型別的型別說明符之一。在此情況下,宣告必須至少宣告一個變數,且每個變數都必須具有非空的初始化式。
// “auto”s in declaration specifiers auto x = 5; // OK: x has type int const auto *v = &x, u = 6; // OK: v has type const int*, u has type const int static auto y = 0.0; // OK: y has type double auto f() -> int; auto (*fp)() -> auto = f; // OK: the “auto” in the trailing return type // can be deduced from f
結構化繫結宣告auto 說明符可用於結構化繫結宣告中。 |
(自 C++17 起) |
[編輯] new 運算式
佔位符型別可用於 new 運算式的型別 ID (type-id) 的型別說明符序列中。在此類型別 ID 中,佔位符型別必須作為型別說明符序列中的其中一個型別說明符,或是指定替換該型別說明符之型別的後置回傳型別出現。
函式型別轉換auto 型別說明符可用作函式型別轉換 (function-style cast) 的型別說明符。 |
(自 C++23 起) |
[編輯] 附註
在 C++11 之前,auto 具有儲存期說明符的語意。
在上述未明確規定的上下文中,若程式使用了佔位符型別,則該程式為格式錯誤 (ill-formed)。
若宣告同時宣告了多個實體,且宣告說明符序列使用了佔位符型別,若滿足以下任一條件,程式即為格式錯誤:
- 宣告的部分實體不是變數。
- 在每次推導中,替換佔位符型別的型別不一致。
auto f() -> int, i = 0; // Error: declares a function and a variable with “auto” auto a = 5, b = {1, 2}; // Error: different types for “auto”
|
auto 關鍵字亦可用於巢狀名稱說明符中。形式為 auto:: 的巢狀名稱說明符是一個佔位符,它將根據受約束型別佔位符推導的規則,被替換為類別或列舉型別。 |
(概念 TS) |
| 特性測試巨集 | 數值 | 標準 | 功能 |
|---|---|---|---|
__cpp_decltype_auto |
201304L |
(C++14) | decltype(auto) |
[編輯] 關鍵字
[編輯] 範例
#include <iostream> #include <utility> template<class T, class U> auto add(T t, U u) { return t + u; } // the return type is the type of operator+(T, U) // perfect forwarding of a function call must use decltype(auto) // in case the function it calls returns by reference template<class F, class... Args> decltype(auto) PerfectForward(F fun, Args&&... args) { return fun(std::forward<Args>(args)...); } template<auto n> // C++17 auto parameter declaration auto f() -> std::pair<decltype(n), decltype(n)> // auto can't deduce from brace-init-list { return {n, n}; } int main() { auto a = 1 + 2; // type of a is int auto b = add(1, 1.2); // type of b is double static_assert(std::is_same_v<decltype(a), int>); static_assert(std::is_same_v<decltype(b), double>); auto c0 = a; // type of c0 is int, holding a copy of a decltype(auto) c1 = a; // type of c1 is int, holding a copy of a decltype(auto) c2 = (a); // type of c2 is int&, an alias of a std::cout << "before modification through c2, a = " << a << '\n'; ++c2; std::cout << " after modification through c2, a = " << a << '\n'; auto [v, w] = f<0>(); //structured binding declaration auto d = {1, 2}; // OK: type of d is std::initializer_list<int> auto n = {5}; // OK: type of n is std::initializer_list<int> // auto e{1, 2}; // Error as of DR n3922, std::initializer_list<int> before auto m{5}; // OK: type of m is int as of DR n3922, initializer_list<int> before // decltype(auto) z = { 1, 2 } // Error: {1, 2} is not an expression // auto is commonly used for unnamed types such as the types of lambda expressions auto lambda = [](int x) { return x + 3; }; // auto int x; // valid C++98, error as of C++11 // auto x; // valid C, error in C++ [](...){}(c0, c1, v, w, d, n, m, lambda); // suppresses "unused variable" warnings }
可能輸出
before modification through c2, a = 3 after modification through c2, a = 4
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯應用於之前的 C++ 標準。
| DR | 應用於 | 出版時的行為 | 正確的行為 |
|---|---|---|---|
| CWG 1265 | C++11 | 原 auto 說明符可用於宣告帶有後置 回傳型別的函式,並在同一個宣告陳述式中定義變數 |
禁止 |
| CWG 1346 | C++11 | 括號括起的運算式列表無法指派給 auto 變數 | 已允許 |
| CWG 1347 | C++11 | 含有 auto 說明符的宣告可能會定義兩個 型別分別為 T 和 std::initializer_list<T> 的變數 |
禁止 |
| CWG 1852 | C++14 | decltype(auto) 中的 auto 說明符同樣是一個佔位符 | 並非「非佔位符」 在此情況下 |
| CWG 1892 | C++11 | 函式指標型別 ID 的回傳型別可為 auto | 禁止 |
| CWG 2476 | C++11 | CWG 1892 號議題的決議禁止了 從初始化式推導函式指標變數的回傳型別 |
已允許 |
[編輯] 參考資料
- C++23 標準 (ISO/IEC 14882:2024)
- 9.2.9.6 Placeholder type specifiers [dcl.spec.auto]
- C++20 標準 (ISO/IEC 14882:2020)
- 9.2.8.5 Placeholder type specifiers [dcl.spec.auto]
- C++17 標準 (ISO/IEC 14882:2017)
- 10.1.7.4 The
autospecifier [dcl.spec.auto]
- 10.1.7.4 The
- C++14 標準 (ISO/IEC 14882:2014)
- 7.1.6.4
autospecifier [dcl.spec.auto]
- 7.1.6.4
- C++11 標準 (ISO/IEC 14882:2011)
- 7.1.6.4
autospecifier [dcl.spec.auto]
- 7.1.6.4