上传cppreference
This commit is contained in:
177
web/cppreference-zh/chmhelp/cpp-language-variadic_arguments.html
Normal file
177
web/cppreference-zh/chmhelp/cpp-language-variadic_arguments.html
Normal file
@@ -0,0 +1,177 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh" dir="ltr" class="client-nojs" xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
|
||||
<head><meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>变长实参</title>
|
||||
<link rel="stylesheet" href="ext.css" />
|
||||
<link rel="stylesheet" href="site_modules.css" />
|
||||
</head>
|
||||
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-cpp_language_variadic_arguments skin-cppreference2 action-view cpp-navbar">
|
||||
<div id="cpp-content-base">
|
||||
<div id="content"><a id="top"></a>
|
||||
<h1 id="firstHeading" class="firstHeading">变长实参</h1>
|
||||
<div id="bodyContent">
|
||||
<div id="contentSub"><span class="subpages">< <a href="cpp.html">cpp</a>‎ | <a href="cpp-language.html">language</a></span></div>
|
||||
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
||||
<p>允许函数接受任意数量的额外实参。</p>
|
||||
<p>由跟在<a href="cpp-language-function.html">函数声明</a>的 <span class="t-spar">形参列表</span> 之后的<span class="t-rev-inl t-since-cxx11"><span>(并非引入包展开的)</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>尾随 <span class="t-c"><span class="mw-geshi cpp source-cpp">...</span></span> 指定。</p>
|
||||
<p><span class="t-spar">形参列表</span> 非空时,指示变参函数的 <span class="t-c"><span class="mw-geshi cpp source-cpp">...</span></span> 之前可以出现逗号。这是为了兼容 C(从 C++ 采纳函数原型时,C 向其添加了逗号的要求)。</p>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="co1">// 函数声明如下</span>
|
||||
<span class="kw4">int</span> printx<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> fmt, ...<span class="br0">)</span><span class="sy4">;</span>
|
||||
<span class="co1">// 能以一个或多个实参调用:</span>
|
||||
printx<span class="br0">(</span><span class="st0">"hello world"</span><span class="br0">)</span><span class="sy4">;</span>
|
||||
printx<span class="br0">(</span><span class="st0">"a=%d b=%d"</span>, a, b<span class="br0">)</span><span class="sy4">;</span>
|
||||
|
||||
<span class="kw4">int</span> printx<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> fmt...<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 同上(为兼容 C 而允许额外的逗号)</span>
|
||||
<span class="kw4">int</span> printy<span class="br0">(</span>..., <span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> fmt<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误:... 不能作为形参出现</span>
|
||||
<span class="kw4">int</span> printz<span class="br0">(</span>...<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 合法,但无法可移植地访问参数</span></pre></div>
|
||||
</div>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx11">
|
||||
<td>
|
||||
<p>注意:这与函数<a href="cpp-language-parameter_pack.html">形参包</a>展开不同,形参包展开是由作为形参声明符一部分的省略号指定的,而非由出现在所有形参声明之后的省略号。形参包展开和“变参”省略号都能出现在函数模板声明中,如 <span class="t-lc"><a href="cpp-types-is_function.html">std::is_function</a></span> 的情况。</p>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<h3><span class="mw-headline" id=".E9.BB.98.E8.AE.A4.E8.BD.AC.E6.8D.A2">默认转换</span></h3>
|
||||
<p>调用变参函数时,进行左值到右值、数组到指针及函数到指针的<a href="cpp-language-implicit_conversion.html#.E5.80.BC.E5.8F.98.E6.8D.A2">转换</a>后,可变实参列表中的每个实参都要经过称为<i>默认实参提升</i>的额外转换:</p>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx11">
|
||||
<td>
|
||||
<ul>
|
||||
<li>转换 <span class="t-lc"><a href="cpp-types-nullptr_t.html">std::nullptr_t</a></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">void</span><span class="sy2">*</span></span></span></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<ul>
|
||||
<li>转换 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">float</span></span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">double</span></span></span>,如同<a href="cpp-language-implicit_conversion.html#.E6.B5.AE.E7.82.B9.E7.B1.BB.E5.9E.8B.E6.8F.90.E5.8D.87">浮点提升</a></li>
|
||||
<li>转换 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">char</span></span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">short</span></span></span> 及无作用域枚举到 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span></span></span> 或更宽的整数类型,如同<a href="cpp-language-implicit_conversion.html#.E6.95.B4.E5.9E.8B.E6.8F.90.E5.8D.87">整型提升</a></li>
|
||||
</ul>
|
||||
<p>只能有算术、枚举、指针、成员指针及类类型的(转换后的)额外实参。然而,<span class="t-rev-inl t-until-cxx11"><span>非 POD 类类型</span> <span><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></span></span><span class="t-rev-inl t-since-cxx11"><span>拥有合格的非平凡复制构造函数、合格的非平凡移动构造函数或非平凡析构函数的类类型,以及有作用域枚举类型</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>在潜在求值的调用中是以实现定义的语义条件性支持的(这些类型在<a href="cpp-language-expressions.html#.E4.B8.8D.E6.B1.82.E5.80.BC.E8.A1.A8.E8.BE.BE.E5.BC.8F">不求值调用</a>中始终支持)。</p>
|
||||
<p>因为变长形参对于<a href="cpp-language-overload_resolution.html">重载决议</a>而言具有最低的优先级,所以它们常被用作 <a href="cpp-language-sfinae.html">SFINAE</a> 中的万应后备(catch-all fallback)。</p>
|
||||
<p>在使用变长实参的函数体内,可以用一些 <a href="cpp-utility-variadic.html"><code><cstdarg></code> 库设施</a>访问这些实参的值:</p>
|
||||
<table class="t-dsc-begin">
|
||||
<tr class="t-dsc-header">
|
||||
<td colspan="2">
|
||||
<div>定义于头文件 <code><a href="cpp-header-cstdarg.html"><cstdarg></a></code></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="t-dsc">
|
||||
<td>
|
||||
<div class="t-dsc-member-div">
|
||||
<div><a href="cpp-utility-variadic-va_start.html"><span class="t-lines"><span>va_start</span></span></a></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>启用对可变函数实参的访问<br />
|
||||
<span class="t-mark">(宏函数)</span></td>
|
||||
</tr>
|
||||
<tr class="t-dsc">
|
||||
<td>
|
||||
<div class="t-dsc-member-div">
|
||||
<div><a href="cpp-utility-variadic-va_arg.html"><span class="t-lines"><span>va_arg</span></span></a></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>访问下一个可变函数实参<br />
|
||||
<span class="t-mark">(宏函数)</span></td>
|
||||
</tr>
|
||||
<tr class="t-dsc">
|
||||
<td>
|
||||
<div class="t-dsc-member-div">
|
||||
<div><a href="cpp-utility-variadic-va_copy.html"><span class="t-lines"><span>va_copy</span></span></a></div>
|
||||
<div><span class="t-lines"><span><span class="t-mark-rev t-since-cxx11">(C++11)</span></span></span></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>制造可变函数实参的副本<br />
|
||||
<span class="t-mark">(宏函数)</span></td>
|
||||
</tr>
|
||||
<tr class="t-dsc">
|
||||
<td>
|
||||
<div class="t-dsc-member-div">
|
||||
<div><a href="cpp-utility-variadic-va_end.html"><span class="t-lines"><span>va_end</span></span></a></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>结束对可变函数实参的遍历<br />
|
||||
<span class="t-mark">(宏函数)</span></td>
|
||||
</tr>
|
||||
<tr class="t-dsc">
|
||||
<td>
|
||||
<div class="t-dsc-member-div">
|
||||
<div><a href="cpp-utility-variadic-va_list.html"><span class="t-lines"><span>va_list</span></span></a></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>保有 va_start、va_arg、va_end 和 va_copy 所需的信息<br />
|
||||
<span class="t-mark">(typedef)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>如果省略号前的最后一个形参具有引用类型,或其类型与默认实参提升所产生的各种类型不兼容,那么 <span class="t-lc"><a href="cpp-utility-variadic-va_start.html">va_start</a></span> 宏的行为未定义。</p>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx11">
|
||||
<td>
|
||||
<p>如果在 <span class="t-lc"><a href="cpp-utility-variadic-va_start.html">va_start</a></span> 中以<a href="cpp-language-parameter_pack.html#.E5.8C.85.E5.B1.95.E5.BC.80">包展开</a>或源自 <a href="cpp-language-lambda.html#Lambda_.E6.8D.95.E8.8E.B7">lambda 捕获</a>的实体为最后的形参,那么程序非良构,不要求诊断。</p>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<h3><span class="mw-headline" id=".E6.9B.BF.E4.BB.A3.E6.96.B9.E6.A1.88">替代方案</span></h3>
|
||||
<table class="t-rev-begin">
|
||||
<tr class="t-rev t-since-cxx11">
|
||||
<td>
|
||||
<ul>
|
||||
<li><a href="cpp-language-parameter_pack.html">变参模板</a>也可以用来创建接受可变数量实参的函数。它们通常是更好的选择,因为它们对实参类型不施加任何制约,不进行整型和浮点提升,且类型安全。</li>
|
||||
<li>当所有变长实参均为相同类型时,<span class="t-lc"><a href="cpp-utility-initializer_list.html">std::initializer_list</a></span> 提供了一种访问变长实参的便利机制。不过这种情况下不能修改各个实参,因为 <span class="t-lc"><a href="cpp-utility-initializer_list.html">std::initializer_list</a></span> 仅提供指向其各元素的 const 指针。</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
||||
<p>因为在 C 编程语言中,省略号前必须至少出现一个具名形参,所以 <code>printz(...);</code> 非法。C++ 中允许这种形式,尽管无法访问传递给这种函数的实参,此形式常用作 <a href="cpp-language-sfinae.html">SFINAE</a> 的后备重载,它利用了<a href="cpp-language-overload_resolution.html">重载决议</a>中省略号转换的最低优先级。</p>
|
||||
<p>变长实参的语法在 1983 年引入 C++,省略号前没有逗号。C89 从 C++ 接受函数原型时,它以要求逗号的语法替换了该语法。为了兼容,C++98 一并接受 C++ 风格 <span class="t-c"><span class="mw-geshi cpp source-cpp">f<span class="br0">(</span><span class="kw4">int</span> n...<span class="br0">)</span></span></span> 和 C 风格 <span class="t-c"><span class="mw-geshi cpp source-cpp">f<span class="br0">(</span><span class="kw4">int</span> n, ...<span class="br0">)</span></span></span>。</p>
|
||||
<h3><span class="mw-headline" id=".E7.BC.BA.E9.99.B7.E6.8A.A5.E5.91.8A">缺陷报告</span></h3>
|
||||
<p>下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。</p>
|
||||
<table class="dsctable" style="font-size:0.8em">
|
||||
<tr>
|
||||
<th>DR</th>
|
||||
<th>应用于</th>
|
||||
<th>出版时的行为</th>
|
||||
<th>正确行为</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue506">CWG 506</a></td>
|
||||
<td>C++98</td>
|
||||
<td>传递非 POD 类实参给省略号导致未定义行为</td>
|
||||
<td>使之为条件性支持</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue634">CWG 634</a></td>
|
||||
<td>C++98</td>
|
||||
<td>条件性支持的类类型使某些 SFINAE 手法无法起效</td>
|
||||
<td>如果不求值则始终支持</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue2247">CWG 2247</a></td>
|
||||
<td>C++11</td>
|
||||
<td>不限制传递形参包或 lambda 捕获给 <code>va_start</code></td>
|
||||
<td>改为非良构,不要求诊断</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue2347">CWG 2347</a></td>
|
||||
<td>C++11</td>
|
||||
<td>不明确如何传递有作用域枚举给省略号</td>
|
||||
<td>改为条件性支持</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
||||
<table class="t-dsc-begin"></table>
|
||||
</div>
|
||||
<div class="visualClear"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user