164 lines
13 KiB
HTML
164 lines
13 KiB
HTML
<!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-c_language_generic 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="c.html">c</a>‎ | <a href="c-language.html">language</a></span></div>
|
|
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
|
<p>提供一种基于控制表达式的类型,在编译时选择数个表达式之一的方法。</p>
|
|
<h3><span class="mw-headline" id=".E8.AF.AD.E6.B3.95">语法</span></h3>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>_Generic</b></code> <code><b>(</b></code> <span class="t-spar">控制表达式</span> <code><b>,</b></code> <span class="t-spar">关联列表</span> <code><b>)</b></code></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-c11">(C11 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<p>其中 <span class="t-spar">关联列表</span> 是逗号分隔的关联列表,每个关联拥有语法:</p>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td class="t-sdsc-nopad"><span class="t-spar">类型名</span> <code><b>:</b></code> <span class="t-spar">表达式</span></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td class="t-sdsc-nopad"><code><b>default</b></code> <code><b>:</b></code> <span class="t-spar">表达式</span></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<p>其中</p>
|
|
<table class="t-par-begin">
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">类型名</span></td>
|
|
<td>-</td>
|
|
<td>任何完整的非可变修改的<a href="c-language-types.html">对象类型</a>(即既非 VLA 亦非指向 VLA 的指针)。</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">关联列表</span></td>
|
|
<td>-</td>
|
|
<td>任何表达式(除了<a href="c-language-operator_other.html#.E9.80.97.E5.8F.B7.E8.BF.90.E7.AE.97.E7.AC.A6">逗号运算符</a>),若不使用 <code>default</code> 关联,则其类型必须与 <span class="t-spar">类型名</span> 之一兼容,</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">表达式</span></td>
|
|
<td>-</td>
|
|
<td>任何类型和值类别的表达式(除了<a href="c-language-operator_other.html#.E9.80.97.E5.8F.B7.E8.BF.90.E7.AE.97.E7.AC.A6">逗号运算符</a>)</td>
|
|
</tr>
|
|
</table>
|
|
<p><span class="t-spar">关联列表</span> 中的任意二个 <span class="t-spar">类型名</span> 不能指定<a href="c-language-types.html#.E5.85.BC.E5.AE.B9.E7.B1.BB.E5.9E.8B">兼容类型</a>。使用关键词 <code>default</code> 的关联只能有一个。若不使用 <code>default</code> ,且无一 <span class="t-spar">类型名</span> 与控制表达式类型兼容,则程序无法编译。</p>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>首先, <span class="t-spar">控制表达式</span> 的类型经历<a href="c-language-conversion.html#.E5.B7.A6.E5.80.BC.E8.BD.AC.E6.8D.A2">左值转换</a>。只在类型域中进行转换:它舍弃顶层 cvr 限定符和原子属性,并应用数组到指针/函数到指针变换到控制表达式的类型,而不实例化任何副效应或计算任何值。</p>
|
|
<p>将转换后的类型与来自关联列表中的 <span class="t-spar">类型名</span> 比较。</p>
|
|
<p>若其类型与关联之一的 <span class="t-spar">类型名</span> <a href="c-language-types.html#.E5.85.BC.E5.AE.B9.E7.B1.BB.E5.9E.8B">兼容</a>,则泛型选择的类型、值及<a href="c-language-value_category.html">值类别</a>就是出现于该 <span class="t-spar">类型名</span> 冒号后的表达式的类型、值及值类别。</p>
|
|
<p>若无一 <span class="t-spar">类型名</span> 的类型与 <span class="t-spar">控制表达式</span> 兼容,且提供了 <code>default</code> 关联,则泛型的类型、值及值类别就是出现于 <code>default :</code> 标号后的表达式的类型、值及值类别。</p>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p>决不求值 <span class="t-spar">控制表达式</span> 和未被选择的选项中的 <span class="t-spar">表达式</span> 。</p>
|
|
<p>因为左值转换, <span class="t-c"><span class="mw-geshi c source-c"><span class="st0">"abc"</span></span></span> 匹配 <span class="t-c"><span class="mw-geshi c source-c"><span class="kw4">char</span><span class="sy2">*</span></span></span> 而非 <span class="t-c"><span class="mw-geshi c source-c"><span class="kw4">char</span><span class="br0">[</span><span class="nu0">4</span><span class="br0">]</span></span></span> , <span class="t-c"><span class="mw-geshi c source-c"><span class="br0">(</span><span class="kw4">int</span> <span class="kw4">const</span><span class="br0">)</span><span class="br0">{</span><span class="nu0">0</span><span class="br0">}</span></span></span> 匹配 <span class="t-c"><span class="mw-geshi c source-c"><span class="kw4">int</span></span></span> 而非 <span class="t-c"><span class="mw-geshi c source-c"><span class="kw4">const</span> <span class="kw4">int</span></span></span> 。</p>
|
|
<p>泛型选择中的 <span class="t-spar">表达式</span> 允许任何<a href="c-language-value_category.html">值类别</a>,含函数指代器及 void 表达式,而且若它受到选择,则泛型选择自身拥有相同的值类别。</p>
|
|
<p>C99 中引入的来自 <code><tgmath.h></code> 的<a href="c-numeric-tgmath.html">泛型数学宏</a>,曾是通过编译器限定的行为实现的。 C11 所引入的泛型选择,给予程序员写相似的类型依赖代码的能力。</p>
|
|
<p>泛型选择类似 C++ 中的重载(在编译时基于参数类型选择数个函数之一)。除了它在任意表达式之间选择。</p>
|
|
<h3><span class="mw-headline" id=".E5.85.B3.E9.94.AE.E8.AF.8D">关键词</span></h3>
|
|
<p><a href="c-keyword-_Generic.html"><tt>_Generic</tt></a>, <a href="c-keyword-default.html"><tt>default</tt></a></p>
|
|
<h3><span class="mw-headline" id=".E7.A4.BA.E4.BE.8B">示例</span></h3>
|
|
<div class="t-example">
|
|
<div class="t-example-live-link"></div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="co2">#include <stdio.h></span>
|
|
<span class="co2">#include <math.h></span>
|
|
|
|
<span class="co1">// tgmath.h 宏 cbrt 的可能实现</span>
|
|
<span class="co2">#define cbrt(X) _Generic((X), \
|
|
long double: cbrtl, \
|
|
default: cbrt, \
|
|
float: cbrtf \
|
|
)(X)</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">double</span> x <span class="sy1">=</span> <span class="nu16">8.0</span><span class="sy4">;</span>
|
|
<span class="kw4">const</span> <span class="kw4">float</span> y <span class="sy1">=</span> <span class="nu16">3.375</span><span class="sy4">;</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"cbrt(8.0) = %f<span class="es1">\n</span>"</span>, <a href="c-numeric-math-cbrt.html"><span class="kw666">cbrt</span></a><span class="br0">(</span>x<span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 选择默认的 cbrt</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"cbrtf(3.375) = %f<span class="es1">\n</span>"</span>, <a href="c-numeric-math-cbrt.html"><span class="kw666">cbrt</span></a><span class="br0">(</span>y<span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 将 const float 转换成 float,</span>
|
|
<span class="co1">// 然后选择 cbrtf</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>输出:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="text source-text">
|
|
<pre class="de1">cbrt(8.0) = 2.000000
|
|
cbrtf(3.375) = 1.500000</pre></div>
|
|
</div>
|
|
</div>
|
|
<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="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2396.htm#dr_481">DR 481</a></td>
|
|
<td>C11</td>
|
|
<td>未指定控制表达式是否经历左值转换</td>
|
|
<td>经历</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E5.BC.95.E7.94.A8">引用</span></h3>
|
|
<div class="t-ref-std-17">
|
|
<ul>
|
|
<li>C17 标准(ISO/IEC 9899:2018):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.5.1.1 Generic selection (p: 56-57)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-11">
|
|
<ul>
|
|
<li>C11 标准(ISO/IEC 9899:2011):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.5.1.1 Generic selection (p: 78-79)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|