变长参数

来自cppreference.com
< cpp‎ | language

允许函数接受任意数量的实参。

通过 ... 形式的形参指示,它必须出现在函数声明parameter-list 中。

在语法正确处, , ... 可为 ... 所替换。

// 函数声明如下
int printx(const char* fmt, ...);
// 能以一个或多个参数调用:
printx("hello world");
printx("a=%d b=%d", a, b);
 
int printx(const char* fmt...); // 同上(逗号可选)
int printy(..., const char* fmt); // 错误: ... 必须在最后
int printz(...); // 合法,但无法可移植地访问参数

注意:这异于参数包展开,参数包为作为形参声明器一部分的省略号所指示,而非自身作为形参出现的省略号。参数包展开和省略号参数都能出现在函数模板声明中,与在 std::is_function 中一样。

目录

[编辑] 默认转换

调用变参数函数时,在左值到右值、数组到指针及函数到指针转换后,每个作为可变参数列表的实参都要经过称为默认参数提升的进一步转换:

  • std::nullptr_t 被转换成 void*
  • 如在浮点提升float 被转换成 double
  • 如在整数提升boolcharshort 及无作用域枚举被转换到 int 或更宽的整数类型

仅允许算术、枚举、指针、指向成员指针及类类型参数。

为了重载决议的目的,变长参数拥有最低等级,故它们常用作 SFINAE 中的全部捕获回落。

在使用变长参数的函数体内,这些参数的值可用 <cstdarg> 库设施访问:

定义于头文件 <cstdarg>
令对可变函数参数的访问可行
(宏函数) [编辑]
访问下一个可变函数参数
(宏函数) [编辑]
(C++11)
制造可变函数参数的副本
(宏函数) [编辑]
结束可变参数函数的遍历
(宏函数) [编辑]
保有 va_start 、 va_arg 、 va_end 和 va_copy 所需的信息
(typedef) [编辑]

若省略号前的最后一个参数拥有引用类型,或拥有不与产生自默认参数提升的类型兼容的类型,则 va_start 宏的行为未定义。

[编辑] 替用品

  • 变长模板亦可用于创建可变数量实参的函数。它们通常是更好的选择,因为它们不在实参类型上施以制约,不进行整数和浮点提升,且是类型安全的。(C++11 起)
  • 若所有变长实参均拥有相同类型,则 std::initializer_list 提供访问变长实参的便利机制(以不同语法工作)。(C++11 起)

[编辑] 注意

在 C 编程语言中,省略号前必须至少出现一个具名参数,故 printz(...); 非法。 C++ 中,允许此行为,尽管无法访问传递给这种函数的参数,此形式常用于 SFINAE 的回落重载,它开发了重载决议中省略号转换的最低优先级。

变长参数的语法于 1987 年的 C++ 所引入,无逗号前的省略号。 C89 从 C++ 接受函数原型时,它以要求逗号的语法替换了该语法。为了兼容性, C++98 一并接受 C++ 风格 f(int n...) 和 C 风格 f(int n, ...)

[编辑] 参阅

变长参数C 文档