名稱空間
變體
操作

佔位符型別說明符 (C++11 起)

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
通用主題
流程控制
條件執行語句
if
迭代語句(迴圈)
for
range-for (C++11)
跳轉語句
函式
函式宣告
Lambda 函式表示式
inline 說明符
動態異常規範 (直到 C++17*)
noexcept 說明符 (C++11)
異常
名稱空間
型別
說明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
儲存期說明符
初始化
表示式
替代表示
字面量
布林 - 整型 - 浮點型
字元 - 字串 - nullptr (C++11)
使用者定義 (C++11)
工具
屬性 (C++11)
型別
typedef 宣告
類型別名宣告 (C++11)
型別轉換
記憶體分配
類特有的函式屬性
explicit (C++11)
static

特殊成員函式
模板
雜項
 
 

佔位符型別說明符指定一個佔位符型別,該型別將在稍後被替換,通常透過從初始化器中推匯出來。

目錄

[編輯] 語法

型別約束 (可選) auto (1)
型別約束 (可選) decltype(auto) (2) (C++14 起)
型別約束 - (C++20 起)一個概念名,可選地限定,可選地後跟用<>括起來的模板引數列表
1) 型別使用模板引數推導的規則進行推導。
2) 型別為decltype(expr),其中expr是初始化器或return語句中使用的表示式。

佔位符auto可以伴隨修飾符,例如const&,它們將參與型別推導。佔位符decltype(auto)必須是宣告型別的唯一組成部分。(C++14 起)

如果存在型別約束,令T為佔位符推匯出的型別,則型別約束引入一個約束表示式,如下所示:

  • 如果型別約束Concept<A1, ..., An>,則約束表示式是Concept<T, A1, ..., An>
  • 否則(型別約束Concept而不帶引數列表),約束表示式是Concept<T>

如果約束表示式無效或返回false,則推導失敗。

(C++20 起)

[編輯] 說明

佔位符型別說明符可以出現在以下語境中:

引數宣告

在以下引數宣告中,所宣告引數的型別可以採用語法(1)

  • 如果lambda 表示式的引數具有佔位符型別,則該 lambda 表示式是泛型 lambda。
(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 表示式的 type-id 的型別說明符序列中。在此類 type-id 中,佔位符型別必須作為型別說明符序列中的型別說明符之一,或作為尾隨返回型別,該尾隨返回型別指定替換此類型別說明符的型別。

函式式轉換

auto型別說明符可用作函式式轉換的型別說明符。

(C++23 起)

[編輯] 注意

在 C++11 之前,auto具有儲存期說明符的語義。

在上述未明確說明的上下文中使用佔位符型別的程式是格式錯誤的。

如果一個宣告聲明瞭多個實體,並且宣告說明符序列使用了佔位符型別,則如果滿足以下任何條件,程式將格式錯誤:

  • 宣告的某些實體不是變數。
  • 在每次推導中,替換佔位符型別的型別不相同。
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)

[編輯] 關鍵詞

auto, decltype

[編輯] 示例

#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++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
CWG 1265 C++11 auto說明符可用於宣告帶尾隨返回型別的函式並在一個宣告語句中定義變數。
返回型別並在一個宣告語句中定義變數
已禁止
CWG 1346 C++11 帶括號的表示式列表不能賦值給auto變數 允許
CWG 1347 C++11 帶有auto說明符的宣告可以定義兩個變數
分別為型別Tstd::initializer_list<T>
已禁止
CWG 1852 C++14 decltype(auto)中的auto說明符也是佔位符 不是佔位符
在這種情況下
CWG 1892 C++11 函式指標 type-id 的返回型別可以是auto 已禁止
CWG 2476 C++11 CWG 問題 1892 的解決方案禁止從初始化器推導函式指標變數的返回型別。
從初始化器推導函式指標變數的返回型別
允許

[編輯] 參考資料

  • C++23 標準 (ISO/IEC 14882:2024)
  • 9.2.9.6 佔位符型別說明符 [dcl.spec.auto]
  • C++20 標準 (ISO/IEC 14882:2020)
  • 9.2.8.5 佔位符型別說明符 [dcl.spec.auto]
  • C++17 標準 (ISO/IEC 14882:2017)
  • 10.1.7.4 auto 說明符 [dcl.spec.auto]
  • C++14 標準 (ISO/IEC 14882:2014)
  • 7.1.6.4 auto 說明符 [dcl.spec.auto]
  • C++11 標準 (ISO/IEC 14882:2011)
  • 7.1.6.4 auto 說明符 [dcl.spec.auto]