名稱空間
變體
操作

變長引數

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
表示式
替代表示
字面量
布林(Boolean) - 整型(Integer) - 浮點型(Floating-point)
字元(Character) - 字串(String) - nullptr (C++11)
使用者定義 (C++11)
工具
屬性 (C++11)
型別
typedef 宣告
類型別名宣告 (C++11)
型別轉換
記憶體分配
類特有的函式屬性
explicit (C++11)
static

特殊成員函式
模板
雜項
 
 

允許函式接受任意數量的額外引數。

如果函式的引數列表的最後一個引數是省略號(...),則該函式是變參函式。

省略號之前的逗號可以省略。 (C++26 中已棄用)
// the function declared as follows
int printx(const char* fmt, ...);
int printx(const char* fmt...); // same as above, but deprecated since C++26
 
// may be called with one or more arguments:
printx("hello world");
printx("a=%d b=%d", a, b);
 
int printy(..., const char* fmt); // error: ... can only be the last parameter
int printz(...); // valid, but the arguments cannot be accessed portably

這與函式引數包展開不同,引數包展開由作為引數宣告符一部分的省略號指示,而不是單獨的省略號引數。引數包展開和“變參”省略號都可以出現在函式模板的宣告中,例如std::is_function

(C++11 起)

目錄

[編輯] 預設引數提升

當呼叫變參函式時,在左值到右值、陣列到指標以及函式到指標的轉換之後,作為可變引數列表一部分的每個引數都會進行額外的轉換,稱為預設引數提升

(C++11 起)
  • float 引數被轉換為 double,如浮點提升
  • boolcharshort 和無作用域列舉被轉換為 int 或更寬的整數型別,如整型提升

非 POD 類型別(C++11 前)作用域列舉和具有合格的非平凡複製建構函式、合格的非平凡移動建構函式或非平凡解構函式的類型別(C++11 起) 在潛在求值呼叫中是條件支援的,其語義由實現定義(這些型別在未求值呼叫中始終受支援)。

由於變參引數在過載決議中具有最低的等級,它們通常在 SFINAE 中用作包羅永珍的備用方案。

在使用變參引數的函式體內,可以使用 <cstdarg> 庫工具訪問這些引數的值

定義於標頭檔案 <cstdarg>
啟用對變長函式引數的訪問
(函式宏) [編輯]
訪問下一個變長函式引數
(函式宏) [編輯]
(C++11)
複製變長函式引數
(函式宏) [編輯]
結束變長函式引數的遍歷
(函式宏) [編輯]
儲存 va_startva_argva_endva_copy 所需的資訊
(型別定義) [編輯]

如果省略號之前的最後一個引數具有引用型別,或者其型別與預設引數提升後的型別不相容,則 va_start 宏的行為是未定義的。

如果將包展開或由lambda 捕獲產生的實體用作 va_start 的最後一個引數,則程式格式錯誤,無需診斷。

(C++11 起)

[編輯] 替代方案

  • 變參模板也可以用來建立接受可變數量引數的函式。它們通常是更好的選擇,因為它們不對引數的型別施加限制,不執行整數和浮點提升,並且是型別安全的。
  • 如果所有可變引數都具有共同的型別,則 std::initializer_list 提供了一種方便的機制(儘管語法不同)來訪問可變引數。但是,在這種情況下,引數不能被修改,因為 std::initializer_list 只能提供一個指向其元素的 const 指標。
(C++11 起)

[編輯] 注意

在 C 程式語言中,直到 C23,至少一個命名引數必須出現在省略號引數之前,因此 R printz(...); 在 C23 之前無效。在 C++ 中,即使無法訪問傳遞給此類函式的引數,也允許這種形式,並且通常在 SFINAE 中用作備用過載,利用省略號轉換在過載決議中的最低優先順序。

這種變參語法於 1983 年引入 C++,省略號前沒有逗號。當 C89 從 C++ 採用函式原型時,它用一個需要逗號的語法替換了它。為了相容性,C++98 同時接受 C++ 風格的 f(int n...) 和 C 風格的 f(int n, ...)。原始的 C++ 風格語法自 C++26 起已棄用。

逗號可以在簡寫函式模板中使用,以使省略號表示變參函式而不是變參模板

void f1(auto...);   // 等同於 template<class... Ts> void f3(Ts...)
void f2(auto, ...); // 等同於 template<class T> void f3(T, ...)

(C++20 起)

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
CWG 506 C++98 將非 POD 類引數傳遞給
省略號會導致未定義行為
傳遞此類引數是
條件支援的,且語義由
實現定義
CWG 634 C++98 條件支援的類型別
導致某些 SFINAE 慣用法失效
如果未求值,則始終支援
CWG 2247 C++11 沒有限制將引數包
或 lambda 捕獲傳遞給 va_start
導致格式錯誤,
無需診斷
CWG 2347 C++11 不清楚傳遞給省略號的
作用域列舉是否受預設引數提升影響
傳遞作用域列舉
是條件支援的,且語義由
實現定義

[編輯] 參閱

C 文件 關於 變參(Variadic arguments)
C 文件 關於 隱式轉換(Implicit conversions)