777 lines
127 KiB
HTML
777 lines
127 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-cpp_language_overload_resolution 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>为了编译函数调用,编译器必须首先进行<a href="cpp-language-lookup.html">名字查找</a>,对于函数可能涉及<a href="cpp-language-adl.html">实参依赖查找</a>,而对于函数模板可能后随<a href="cpp-language-template_argument_deduction.html">模板实参推导</a>。如果这些步骤产生了多个<i>候选函数</i>,那么需要进行<i>重载决议</i>选择将要实际调用的函数。</p>
|
|
<p>通常来说,所调用的函数是各形参与各实参之间的匹配最紧密的候选函数。</p>
|
|
<p>关于其他可以出现重载函数名的语境,见<a href="cpp-language-overloaded_address.html">重载函数的地址</a>。</p>
|
|
<p>如果函数无法被重载决议选择(例如它是有未被满足的<a href="cpp-language-constraints.html">约束</a>的<a href="cpp-language-templates.html#.E6.A8.A1.E6.9D.BF.E5.8C.96.E5.AE.9E.E4.BD.93">模板化实体</a>),那么不能指名或再使用它。</p>
|
|
<h3><span class="mw-headline" id=".E7.BB.86.E8.8A.82">细节</span></h3>
|
|
<p>重载决议开始前,将名字查找和模板实参推导所选择的函数组成<i>候选函数</i>的集合(确切的判别标准取决于发生重载决议的语境,见下文)。</p>
|
|
<p>如果有候选函数是除构造函数外的<a href="cpp-language-member_functions.html">成员函数</a>(静态或非静态),那么将它当做如同它有一个额外形参(<i>隐式对象形参</i>),代表调用函数所用的对象,并出现在首个实际形参之前。</p>
|
|
<p>类似地,调用成员函数所用的对象会作为<i>隐含对象实参</i>前附于实参列表。</p>
|
|
<p>对于类 <code>X</code> 的成员函数,隐含对象形参的类型受成员函数的 cv 限定和引用限定影响,如<a href="cpp-language-member_functions.html">成员函数</a>中所述。</p>
|
|
<p>就确定<i>隐式对象形参</i>类型而言,用户定义转换函数被认为是<i>隐含对象实参</i>的成员。</p>
|
|
<p>就确定<i>隐式对象形参</i>类型而言,由 using 声明引入到派生类中的成员函数被认为是派生类的成员。</p>
|
|
<p>对于静态成员函数,其<i>隐式对象形参</i>被认为匹配任何对象:不检验其类型,且不为其尝试转换序列。</p>
|
|
<p>对于重载决议的剩余部分,<i>隐含对象实参</i>与其他实参不可辨别,但下列特殊规则适用于<i>隐式对象形参</i>:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 不能对隐式对象形参运用用户定义转换</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 右值能绑定到非 const 的隐式对象形参<span class="t-rev-inl t-since-cxx11"><span>(除非是对引用限定的成员函数)</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>,且不影响隐式转换的等级。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> B <span class="br0">{</span> <span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> A <span class="br0">{</span> operator B<span class="sy3">&</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
A a<span class="sy4">;</span>
|
|
a.<span class="me1">B</span><span class="sy4">::</span><span class="me2">f</span><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误:不能对隐式对象形参运用用户定义转换</span>
|
|
<span class="kw1">static_cast</span><span class="sy1"><</span>B<span class="sy3">&</span><span class="sy1">></span><span class="br0">(</span>a<span class="br0">)</span>.<span class="me1">f</span><span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<p>如果有候选函数是函数模板,那么使用<a href="cpp-language-template_argument_deduction.html">模板实参推导</a>生成其特化,并把这种特化当做非模板函数对待,但在决断规则中另行有所规定。如果一个名字指代一个或多个函数模板,并且同时指代重载的非模板函数,那么这些函数和从模板生成的特化都是候选。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>如果构造函数模板或转换函数模板拥有在推导后它恰好为<a href="cpp-language-dependent_name.html#.E5.80.BC.E5.BE.85.E5.86.B3.E8.A1.A8.E8.BE.BE.E5.BC.8F">值待决的</a><a href="cpp-language-explicit.html">条件性 explicit 说明符</a>,且语境要求非 explicit 的候选而所生成的候选为 explicit,那么从候选集中移除它。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>候选函数列表中始终不包含被定义为弃置的预置<a href="cpp-language-move_constructor.html">移动构造函数</a>和<a href="cpp-language-move_assignment.html">移动赋值运算符</a>。</p>
|
|
<p>在构造派生类对象时,候选函数列表中不包含继承的复制和移动构造函数。</p>
|
|
<h3><span class="mw-headline" id=".E5.80.99.E9.80.89.E5.87.BD.E6.95.B0">候选函数</span></h3>
|
|
<p>使用重载决议的每种语境都以其独有的方式准备其候选函数集合和实参列表:</p>
|
|
<h4><span class="mw-headline" id=".E8.B0.83.E7.94.A8.E5.85.B7.E5.90.8D.E5.87.BD.E6.95.B0">调用具名函数</span></h4>
|
|
<p>如果 <code>E</code> 在<a href="cpp-language-operator_other.html#.E5.86.85.E5.BB.BA.E7.9A.84.E5.87.BD.E6.95.B0.E8.B0.83.E7.94.A8.E8.BF.90.E7.AE.97.E7.AC.A6">函数调用表达式</a> <code>E(args)</code> 中指名重载的函数和/或函数模板(但非可调用对象)的集合,那么遵循下列规则:</p>
|
|
<ul>
|
|
<li>如果表达式 <code>E</code> 具有 <code>PA->B</code> 或 <code>A.B</code> 的形式(其中 A 具有类类型 cv T),那么将 <code>B</code> 作为 <code>T</code> 的成员函数<a href="cpp-language-lookup.html">查找</a>。该查找所找到的函数声明都是候选函数。就重载决议而言,实参列表拥有 cv T 类型的隐含对象实参。</li>
|
|
<li>如果表达式 <code>E</code> 是<a href="cpp-language-expressions.html#.E5.88.9D.E7.AD.89.E8.A1.A8.E8.BE.BE.E5.BC.8F">初等表达式</a>,那么遵循函数调用的正常规则<a href="cpp-language-lookup.html">查找</a>它的名字(可能涉及 <a href="cpp-language-adl.html">ADL</a>)。该查找所找到的函数声明(取决于查找的工作方式)为下列之一:</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>a) 全部是非成员函数(该情况下,就重载决议而言,实参列表正是函数调用表达式中所用的实参列表)</dd>
|
|
<dd>b) 全部是某个类 <code>T</code> 的成员函数,该情况下,如果 <a href="cpp-language-this.html">this</a> 在作用域中且为指向 <code>T</code> 或从 <code>T</code> 派生的类的指针,则以 <code>*this</code> 为隐含对象实参。否则(如果 <code>this</code> 不在作用域中或不指向 <code>T</code>),以一个 <code>T</code> 类型的虚假对象为隐含对象实参,而如果重载决议继而选择了非静态成员函数,那么程序非良构。</dd>
|
|
</dl>
|
|
<h4><span class="mw-headline" id=".E8.B0.83.E7.94.A8.E7.B1.BB.E5.AF.B9.E8.B1.A1">调用类对象</span></h4>
|
|
<p>如果 <code>E</code> 在<a href="cpp-language-operator_other.html#.E5.86.85.E5.BB.BA.E7.9A.84.E5.87.BD.E6.95.B0.E8.B0.83.E7.94.A8.E8.BF.90.E7.AE.97.E7.AC.A6">函数调用表达式</a> <code>E(args)</code> 中拥有类型 cv <code>T</code>,那么</p>
|
|
<ul>
|
|
<li>在表达式 <code>(E).operator()</code> 的语境中,对名字进行 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="br0">(</span><span class="br0">)</span></span></span> 的通常<a href="cpp-language-lookup.html">查找</a>获得 T 的函数调用运算符,并把每个找到的函数声明添加到候选函数集。</li>
|
|
<li>对于 <code>T</code> 或 <code>T</code> 的基类中每个(未被隐藏的)非 explicit 的<a href="cpp-language-cast_operator.html">用户定义转换函数</a>,且其 cv 限定符与 <code>T</code> 的 cv 限定符相同或更多,并且该转换函数转换到:</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>函数指针</li>
|
|
<li>函数指针的引用</li>
|
|
<li>函数的引用</li>
|
|
</ul>
|
|
</dd>
|
|
<dd>那么将一个拥有独有名称的<i>代表调用函数</i>添加到候选函数集,该函数的首个形参为转换结果,剩余各形参为转换结果所接受的形参列表,而其返回类型为转换结果的返回类型。如果后继的重载决议选择此代表函数,那么将调用用户定义转换函数,然后调用转换的结果。</dd>
|
|
</dl>
|
|
<p>任何情况下,就重载决议而言的实参列表,是函数调用表达式的实参列表,前面加上隐含对象实参 <code>E</code>(匹配到代表函数时,用户定义转换将自动将隐含对象实参转换为代表函数的首个实参)。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">int</span> f1<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> f2<span class="br0">(</span><span class="kw4">float</span><span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
<span class="kw1">struct</span> A
|
|
<span class="br0">{</span>
|
|
<span class="kw1">using</span> fp1 <span class="sy1">=</span> <span class="kw4">int</span><span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span>
|
|
operator fp1<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> f1<span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// 转换到函数指针的转换函数</span>
|
|
<span class="kw1">using</span> fp2 <span class="sy1">=</span> <span class="kw4">int</span><span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">float</span><span class="br0">)</span><span class="sy4">;</span>
|
|
operator fp2<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> f2<span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// 转换到函数指针的转换函数</span>
|
|
<span class="br0">}</span> a<span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> i <span class="sy1">=</span> a<span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 通过转换函数返回的指针调用 f1</span></pre></div>
|
|
</div>
|
|
<h4><span class="mw-headline" id=".E8.B0.83.E7.94.A8.E9.87.8D.E8.BD.BD.E8.BF.90.E7.AE.97.E7.AC.A6">调用重载运算符</span></h4>
|
|
<p>如果表达式中某个运算符的至少一个实参具有类类型或枚举类型,那么<a href="cpp-language-expressions.html#.E8.BF.90.E7.AE.97.E7.AC.A6">内建运算符</a>和<a href="cpp-language-operators.html">用户定义的运算符重载</a>都参与重载决议,所选择的候选函数集如下:</p>
|
|
<p>对于实参具有类型 <code>T1</code>(移除 cv 限定后)的一元运算符 <code><b>@</b></code>,或左操作数具有类型 <code>T1</code> 而右操作数具有类型 <code>T2</code>(移除 cv 限定后)的二元运算符 <code><b>@</b></code>,准备下列候选函数集:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> <i>成员候选</i>:如果 <code>T1</code> 是完整类或当前正在定义的类,那么成员候选集是对 <code>T1::operator@</code> 进行<a href="cpp-language-lookup.html">有限定的名字查找</a>的结果。所有其他情况下,成员候选集为空。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> <i>非成员候选</i>:对于<a href="cpp-language-operators.html">运算符重载</a>容许非成员形式的运算符,为在表达式的语境中对 <code>operator@</code> 进行<a href="cpp-language-lookup.html">无限定名字查找</a>(可能涉及 <a href="cpp-language-adl.html">ADL</a>)所找到的所有声明,但忽略成员函数声明而且其不会阻止到下个外围作用域中继续进行查找。如果二元运算符的两个操作数,或一元运算符的唯一操作数具有枚举类型,那么只查找有形参具有该枚举类型(或到该枚举类型引用)的函数,成为非成员候选函数。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> <i>内建候选</i>:对于 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator,</span></span>、一元 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy3">&</span></span></span> 和 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy2">-</span><span class="sy1">></span></span></span>,内建候选集为空。对于其他运算符,内建候选是<a href="cpp-language-expressions.html#.E8.BF.90.E7.AE.97.E7.AC.A6">内建运算符页面</a>中列出的函数,只要所有操作数都能隐式转换为其各个形参。如果有任何内建候选拥有的形参列表与某个并非函数模板特化的非成员候选相同,那么该内建候选不会添加到内建候选列表。当考虑内建的赋值运算符时,限制从其左侧实参进行的转换:不考虑用户定义转换。</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">4)</span> <i>重写候选</i>:
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>对于四个关系运算符表达式 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy1"><</span>y</span></span> 、 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy1"><=</span>y</span></span> 、 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy1">></span>y</span></span> 及 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy1">>=</span>y</span></span> ,添加所有找到的成员、非成员及内建 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1"><=></span></span></span> 到集合。</li>
|
|
<li>对于四个关系运算符表达式 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy1"><</span>y</span></span> 、 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy1"><=</span>y</span></span> 、 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy1">></span>y</span></span> 及 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy1">>=</span>y</span></span> 还有三路比较运算符表达式 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy1"><=></span>y</span></span> ,对每个找到的成员、非成员及内建 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1"><=></span></span></span> 添加两个形参顺序相反的对应合成候选。</li>
|
|
<li>对于 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy3">!</span><span class="sy1">=</span>y</span></span> ,添加所有找到的成员、非成员及内建 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1">==</span></span></span> 到集合。</li>
|
|
<li>对于相等运算符表达式 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy1">==</span>y</span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp">x<span class="sy3">!</span><span class="sy1">=</span>y</span></span> ,对每个找到的成员、非成员及内建 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1">==</span></span></span> 添加两个个形参顺序相反的对应合成候选。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<p>所有情况下,在重写表达式的语境中不考虑重写候选。对于所有其他运算符,重写候选集为空。</p>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>提交给重载决议的候选函数集合是以上集合的并集。就重载决议而言的实参列表由运算符的各操作数组成,除了 <code>operator-></code> 的情况,其第二操作数并非函数调用的实参(见<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E6.88.90.E5.91.98.E8.AE.BF.E9.97.AE.E8.BF.90.E7.AE.97.E7.AC.A6">成员访问运算符</a>)。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span>
|
|
operator <span class="kw4">int</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 用户定义转换</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
A operator<span class="sy2">+</span><span class="br0">(</span><span class="kw4">const</span> A<span class="sy3">&</span>, <span class="kw4">const</span> A<span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 非成员用户定义运算符</span>
|
|
|
|
<span class="kw4">void</span> m<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
A a, b<span class="sy4">;</span>
|
|
a <span class="sy2">+</span> b<span class="sy4">;</span> <span class="co1">// 成员候选:无</span>
|
|
<span class="co1">// 非成员候选:operator+(a,b)</span>
|
|
<span class="co1">// 内建候选:int(a) + int(b)</span>
|
|
<span class="co1">// 重载决议选择 operator+(a,b)</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>如果重载决议选择了内建候选,那么从类类型的操作数进行的<a href="cpp-language-implicit_conversion.html">用户定义转换序列</a>不允许拥有第二个标准转换序列:用户定义转换函数必须直接给出期待的操作数类型:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> Y <span class="br0">{</span> operator <span class="kw4">int</span><span class="sy2">*</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// Y 可转换到 int*</span>
|
|
<span class="kw4">int</span> <span class="sy2">*</span>a <span class="sy1">=</span> Y<span class="br0">(</span><span class="br0">)</span> <span class="sy2">+</span> <span class="nu16">100.0</span><span class="sy4">;</span> <span class="co1">// 错误:指针和 double 之间没有 operator+</span></pre></div>
|
|
</div>
|
|
<p>对于 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator,</span></span>、一元 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy3">&</span></span></span> 和 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy2">-</span><span class="sy1">></span></span></span>,如果候选函数集中没有可行函数(见后述),那么将运算符解释为内建运算符。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>如果对运算符 <code>@</code> 的重载决议选择了重写的 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1"><=></span></span></span> 候选,那么用重写的 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1"><=></span></span></span> 候选将 <span class="t-c"><span class="mw-geshi cpp source-cpp">x @ y</span></span> 解释为重写的表达式:当所选择的候选是具有逆序形参的合成候选时,解释为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="nu0">0</span> @ <span class="br0">(</span>y <span class="sy1"><=></span> x<span class="br0">)</span></span></span>,否则为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="br0">(</span>x <span class="sy1"><=></span> y<span class="br0">)</span> @ <span class="nu0">0</span></span></span>。</p>
|
|
<p>如果对运算符(为 <code>==</code> 或 <code>!=</code> )的重载决议选择了重写 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1">==</span></span></span> 候选,那么它的返回类型必须是(可有 cv 限定的) <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">operator<span class="sy1">==</span></span></span> 候选解释 <span class="t-c"><span class="mw-geshi cpp source-cpp">x @ y</span></span> 为重写表达式:如果选择的候选为拥有逆序形参的合成候选则为 <span class="t-c"><span class="mw-geshi cpp source-cpp">y <span class="sy1">==</span> x</span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">!</span><span class="br0">(</span>y <span class="sy1">==</span> x<span class="br0">)</span></span></span> ,否则为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">!</span><span class="br0">(</span>x <span class="sy1">==</span> y<span class="br0">)</span></span></span> 。</p>
|
|
<p>这种情况下的重载决议有一条决胜规则:偏好非重写候选甚于重写候选,且偏好非合成重写候选甚于合成重写候选。</p>
|
|
<p>这种具有逆序实参的查找使得可以只写 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1"><=></span><span class="br0">(</span><a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a>, <span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span><span class="br0">)</span></span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1">==</span><span class="br0">(</span><a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a>, <span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span><span class="br0">)</span></span></span> 就生成 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a></span></span> 和 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span></span></span> 间的所有双向比较。更多细节见<a href="cpp-language-default_comparisons.html">默认比较</a>。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h4><span class="mw-headline" id=".E7.94.B1.E6.9E.84.E9.80.A0.E5.87.BD.E6.95.B0.E5.88.9D.E5.A7.8B.E5.8C.96">由构造函数初始化</span></h4>
|
|
<p>当对类类型的对象进行<a href="cpp-language-direct_initialization.html">直接初始化</a>或在<a href="cpp-language-copy_initialization.html">复制初始化</a>之外的语境中进行<a href="cpp-language-default_initialization.html">默认初始化</a>时,候选函数是正在初始化的类的所有构造函数。实参列表是初始化器的表达式列表。</p>
|
|
<p>当对类类型对象从某个相同或派生类类型的对象进行复制初始化,或在复制初始化语境中进行默认初始化时,候选函数是正在初始化的类的所有<a href="cpp-language-converting_constructor.html">转换构造函数</a>。实参列表是初始化器的表达式。</p>
|
|
<h4><span class="mw-headline" id=".E9.80.9A.E8.BF.87.E8.BD.AC.E6.8D.A2.E8.BF.9B.E8.A1.8C.E5.A4.8D.E5.88.B6.E5.88.9D.E5.A7.8B.E5.8C.96">通过转换进行复制初始化</span></h4>
|
|
<p>如果类类型对象的<a href="cpp-language-copy_initialization.html">复制初始化</a>要求调用某个用户定义转换以将 cv <code>S</code> 类型的初始化器表达式转换为正在初始化的对象的 cv <code>T</code> 类型,那么下列函数是候选函数:</p>
|
|
<ul>
|
|
<li><code>T</code> 的所有<a href="cpp-language-converting_constructor.html">转换构造函数</a></li>
|
|
<li>从 <code>S</code> 及其各基类(除非隐藏)到 <code>T</code> 或 <code>T</code> 的派生类或到它们的引用的非 explicit 转换函数。如果此复制初始化是 <i>cv</i> <code>T</code> 的直接初始化序列的一部分(对于接受一个到 cv <code>T</code> 的引用的构造函数,初始化要绑定到其首个形参的引用),那么也会考虑 explicit 转换函数。</li>
|
|
</ul>
|
|
<p>无论哪种方式,就重载决议而言的实参列表均由单个实参组成,即初始化器表达式,它将会与构造函数的首个实参或转换函数的隐式对象实参相比较。</p>
|
|
<h4><span class="mw-headline" id=".E9.80.9A.E8.BF.87.E8.BD.AC.E6.8D.A2.E8.BF.9B.E8.A1.8C.E9.9D.9E.E7.B1.BB.E5.88.9D.E5.A7.8B.E5.8C.96">通过转换进行非类初始化</span></h4>
|
|
<p>当非类类型 cv1 <code>T</code> 对象的初始化要求某个<a href="cpp-language-cast_operator.html">用户定义转换函数</a>,以从类类型 cv <code>S</code> 的初始化器表达式转换时,下列函数为候选:</p>
|
|
<ul>
|
|
<li><code>S</code> 及其基类(除非隐藏)中的,产生 <code>T</code> 类型,或可由<a href="cpp-language-implicit_conversion.html">标准转换序列</a>转换到 <code>T</code> 的类型,或到这些类型的引用的非 explicit 用户定义转换函数。对于选择候选函数而言,忽略返回类型上的 cv 限定符。</li>
|
|
<li>如果这是<a href="cpp-language-direct_initialization.html">直接初始化</a>,那么也会考虑 <code>S</code> 及其基类(除非隐藏)中的,产生 <code>T</code> 类型,或可由<a href="cpp-language-implicit_conversion.html">限定性转换</a>转换到 <code>T</code> 的类型,或到这些类型的引用的 explicit 用户定义转换函数。</li>
|
|
</ul>
|
|
<p>无论哪种方式,就重载决议而言的实参列表均由单个实参组成,即初始化器表达式,它将会与转换函数的隐含对象实参相比较。</p>
|
|
<h4><span class="mw-headline" id=".E9.80.9A.E8.BF.87.E8.BD.AC.E6.8D.A2.E8.BF.9B.E8.A1.8C.E5.BC.95.E7.94.A8.E5.88.9D.E5.A7.8B.E5.8C.96">通过转换进行引用初始化</span></h4>
|
|
<p>在将指代 cv1 <code>T</code> 的引用绑定到从初始化器表达式转换到类类型 cv2 <code>S</code> 的左值或右值结果的<a href="cpp-language-reference_initialization.html">引用初始化</a>期间,为候选集选择下列函数:</p>
|
|
<ul>
|
|
<li><code>S</code> 及其基类(除非隐藏)中的到以下类型的非 explicit 用户定义转换函数:</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>(当初始化左值引用或到函数的右值引用时)到 cv2 <code>T2</code> 的左值引用</li>
|
|
<li>(当初始化右值引用或到函数的左值引用时)cv2 <code>T2</code> 或到 cv2 <code>T2</code> 的右值引用</li>
|
|
</ul>
|
|
</dd>
|
|
<dd>其中 cv2 T2 与 cv1 T 引用兼容</dd>
|
|
</dl>
|
|
<ul>
|
|
<li>对于直接初始化,如果 T2 与 T 类型相同或能以限定性转换转换到 T,那么也会考虑 explicit 用户定义转换函数。</li>
|
|
</ul>
|
|
<p>无论哪种方式,就重载决议而言的实参列表均由单个实参组成,即初始化器表达式,它将会与转换函数的隐含对象实参相比较。</p>
|
|
<h4><span class="mw-headline" id=".E5.88.97.E8.A1.A8.E5.88.9D.E5.A7.8B.E5.8C.96">列表初始化</span></h4>
|
|
<p>当非聚合类类型 <code>T</code> 的对象进行<a href="cpp-language-list_initialization.html">列表初始化</a>时,进行两阶段的重载决议。</p>
|
|
<ul>
|
|
<li>在阶段 1,候选函数是 <code>T</code> 的所有初始化器列表构造函数,而就重载决议而言的实参列表由单个初始化器列表实参组成</li>
|
|
<li>如果阶段 1 的重载决议失败则进入阶段 2,其中候选函数是 <code>T</code> 的所有构造函数,而就重载决议而言的实参列表由初始化器列表的各个单独元素所组成。</li>
|
|
</ul>
|
|
<p>如果初始化器列表为空而 <code>T</code> 拥有默认构造函数,那么跳过阶段 1。</p>
|
|
<p>在复制列表初始化中,如果阶段 2 选择 explicit 构造函数,那么初始化非良构(与复制初始化的总体相反,它们甚至不考虑 explicit 构造函数)。</p>
|
|
<h3><span class="mw-headline" id=".E5.8F.AF.E8.A1.8C.E5.87.BD.E6.95.B0">可行函数</span></h3>
|
|
<p>给定以上述方式构造的候选函数集,重载决议的下一步骤是检验各个实参与形参,并将集合缩减为<i>可行函数(viable function)</i>的集合</p>
|
|
<p>为了被包含在可行函数集中,候选函数必须满足下列条件:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 如果有 <code>M</code> 个实参,那么刚好具有 <code>M</code> 个形参的候选函数可行。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 如果有 <code>M</code> 个实参且候选函数的形参少于 <code>M</code> 个,但具有一个<a href="cpp-language-variadic_arguments.html">省略号形参</a>,那么它可行。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 如果有 <code>M</code> 个实参且候选函数的形参多于 <code>M</code> 个,但是第 <code>M+1</code> 个形参和所有后随形参都具有默认实参,那么它可行。对于剩余的重载决议,形参列表被截断到 M。</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">4)</span> 如果函数拥有关联的<a href="cpp-language-constraints.html">约束</a>,那么必须满足它。</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">5)</span> 对于每个实参,必须至少存在一个隐式转换序列将它转换到对应的形参。</div>
|
|
<div class="t-li1"><span class="t-li">6)</span> 如果任何形参具有引用类型,那么这一步负责引用绑定:如果右值实参对应非 const 左值引用形参,或左值实参对应右值引用形参,那么函数不可行。</div>
|
|
<p>禁止用户定义转换(转换构造函数和用户定义转换函数两者)参与可能使得能应用多于一次用户定义转换的隐式转换序列。特别是,如果转换目标是构造函数的首个形参,或用户定义转换函数的隐式对象形参,而该构造/用户定义转换是下列初始化的候选,那么不考虑用户定义转换:</p>
|
|
<ul>
|
|
<li><a href="cpp-language-overload_resolution.html#.E9.80.9A.E8.BF.87.E8.BD.AC.E6.8D.A2.E8.BF.9B.E8.A1.8C.E5.A4.8D.E5.88.B6.E5.88.9D.E5.A7.8B.E5.8C.96">通过用户定义转换进行复制初始化</a>,</li>
|
|
<li><a href="cpp-language-overload_resolution.html#.E9.80.9A.E8.BF.87.E8.BD.AC.E6.8D.A2.E8.BF.9B.E8.A1.8C.E9.9D.9E.E7.B1.BB.E5.88.9D.E5.A7.8B.E5.8C.96">通过转换函数进行非类类型的初始化</a>,</li>
|
|
<li><a href="cpp-language-overload_resolution.html#.E9.80.9A.E8.BF.87.E8.BD.AC.E6.8D.A2.E8.BF.9B.E8.A1.8C.E5.BC.95.E7.94.A8.E5.88.9D.E5.A7.8B.E5.8C.96">为直接引用绑定的通过转换函数进行的初始化</a>,</li>
|
|
<li>在类的<a href="cpp-language-copy_initialization.html">复制初始化</a>的第二步(直接初始化)期间<a href="cpp-language-overload_resolution.html#.E7.94.B1.E6.9E.84.E9.80.A0.E5.87.BD.E6.95.B0.E5.88.9D.E5.A7.8B.E5.8C.96">通过构造函数所作的初始化</a>,</li>
|
|
<li>由列表初始化所作的初始化,其中的初始化器列表刚好拥有一个元素,且其自身是一个初始化器列表,且目标是类 X 的构造函数的首个实参,而该转换是到 X 或到(可为 cv 限定的)X 的引用的转换</li>
|
|
</ul>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span> A<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> B <span class="br0">{</span> B<span class="br0">(</span>A<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
B b<span class="br0">{</span> <span class="br0">{</span><span class="nu0">0</span><span class="br0">}</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// B 的列表初始化</span>
|
|
|
|
<span class="co1">// 候选:B(const B&)、B(B&&)、B(A)</span>
|
|
<span class="co1">// {0} -> B&& 不可行:要调用 B(A)</span>
|
|
<span class="co1">// {0} -> const B& :不可行:要绑定到右值,要调用 B(A)</span>
|
|
<span class="co1">// {0} -> A 可行。调用 A(int):不禁止到 A 的用户定义转换</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E6.9C.80.E4.BD.B3.E5.8F.AF.E8.A1.8C.E5.87.BD.E6.95.B0">最佳可行函数</span></h3>
|
|
<p>对于每对可行函数 <code>F1</code> 和 <code>F2</code>,对从第 <code>i</code> 实参到第 <code>i</code> 形参的转换做排行,以确定哪一个更好(除了首个实参,静态成员函数的<i>隐式对象实参</i>在排行上没有影响)。</p>
|
|
<p>如果 F1 的所有实参的隐式转换<i>不劣于</i> F2 的所有实参的隐式转换,且满足下列条件,那么确定 <code>F1</code> 是优于 <code>F2</code> 的函数:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 至少存在一个 F1 的实参,其隐式转换<i>优于</i> F2 的该实参的对应的隐式转换</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 或若非如此,(只在通过转换进行非类初始化的语境中,)从 F1 的返回类型到要初始化的类型的标准转换序列<i>优于</i>从 F2 的返回类型到该类型的标准转换序列</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">3)</span> 或若非如此,(仅在对函数类型的引用进行直接引用绑定所作的,通过转换函数进行初始化的语境中,)F1 的返回类型是与正在初始化的引用相同种类的引用(左值或右值),而 F2 的返回类型不是</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">4)</span> 或若非如此,F1 是非模板函数而 F2 是模板特化</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 或若非如此,F1 与 F2 都是模板特化,且按照<a href="cpp-language-function_template.html#.E5.87.BD.E6.95.B0.E6.A8.A1.E6.9D.BF.E9.87.8D.E8.BD.BD">模板特化的偏序规则</a>,F1 <i>更特殊</i></div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">6)</span> 或若非如此,F1 与 F2 为拥有相同形参类型列表的非模板函数,且按照<a href="cpp-language-constraints.html">约束的偏序</a>规则,F1 比 F2 更受约束</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">7)</span> 或若非如此,F1 是类 D 的构造函数,F2 是 D 的基类 B 的构造函数,且对应每个实参的 F1 和 F2 的形参均具有相同类型</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">8)</span> 或若非如此,F2 是重写的候选而 F1 不是,</div>
|
|
<div class="t-li1"><span class="t-li">9)</span> 或若非如此,F1 和 F2 都是重写候选,但 F2 是带逆序形参的合成重写候选而 F1 不是</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx17">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">10)</span> 或若非如此,F1 是从<a href="cpp-language-class_template_argument_deduction.html#.E7.94.A8.E6.88.B7.E5.AE.9A.E4.B9.89.E6.8E.A8.E5.AF.BC.E6.8C.87.E5.BC.95">用户定义推导指引</a>所生成的而 F2 不是</div>
|
|
<div class="t-li1"><span class="t-li">11)</span> 或若非如此,F1 是<a href="cpp-language-class_template_argument_deduction.html#.E7.94.A8.E6.88.B7.E5.AE.9A.E4.B9.89.E6.8E.A8.E5.AF.BC.E6.8C.87.E5.BC.95">复制推导候选</a>而 F2 不是</div>
|
|
<div class="t-li1"><span class="t-li">12)</span> 或若非如此,F1 是从非模板构造函数生成而 F2 是从构造函数模板生成
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> <span class="kw1">struct</span> A
|
|
<span class="br0">{</span>
|
|
<span class="kw1">using</span> value_type <span class="sy1">=</span> T<span class="sy4">;</span>
|
|
A<span class="br0">(</span>value_type<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #1</span>
|
|
A<span class="br0">(</span><span class="kw4">const</span> A<span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #2</span>
|
|
A<span class="br0">(</span>T, T, <span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #3</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> U<span class="sy1">></span> A<span class="br0">(</span><span class="kw4">int</span>, T, U<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #4</span>
|
|
<span class="br0">}</span><span class="sy4">;</span> <span class="co1">// #5 为 A(A),为复制推导候选</span>
|
|
|
|
A x <span class="br0">(</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 使用 #3,从非模板构造函数生成</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> A<span class="br0">(</span>T<span class="br0">)</span> <span class="sy2">-</span><span class="sy1">></span> A<span class="sy1"><</span>T<span class="sy1">></span><span class="sy4">;</span> <span class="co1">// #6,不如 #5 特殊</span>
|
|
|
|
A a <span class="br0">(</span><span class="nu0">42</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 使用 #6 推出 A<int> 并用 #1 初始化</span>
|
|
A b <span class="sy1">=</span> a<span class="sy4">;</span> <span class="co1">// 使用 #5 推出 A<int> 并用 #2 初始化</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> A<span class="br0">(</span>A<span class="sy1"><</span>T<span class="sy1">></span><span class="br0">)</span> <span class="sy2">-</span><span class="sy1">></span> A<span class="sy1"><</span>A<span class="sy1"><</span>T<span class="sy1">>></span><span class="sy4">;</span> <span class="co1">// #7,和 #5 一样特殊</span>
|
|
A b2 <span class="sy1">=</span> a<span class="sy4">;</span> <span class="co1">// 使用 #7 推出 A<A<int>> 并用 #1 初始化</span></pre></div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>对所有可行函数进行这些逐对比较。如果刚好有一个可行函数优于所有其他函数,那么重载决议成功并调用该函数。否则编译失败。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">void</span> Fcn<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">int</span><span class="sy2">*</span>, <span class="kw4">short</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
|
|
<span class="kw4">void</span> Fcn<span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span>, <span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #2</span>
|
|
|
|
<span class="kw4">int</span> i<span class="sy4">;</span>
|
|
<span class="kw4">short</span> s <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
Fcn<span class="br0">(</span><span class="sy3">&</span>i, <span class="nu0">1L</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 第 1 个实参:&i -> int* 优于 &i -> const int*</span>
|
|
<span class="co1">// 第 2 个实参:1L -> short 与 1L -> int 等价</span>
|
|
<span class="co1">// 调用 Fcn(int*, int)</span>
|
|
|
|
Fcn<span class="br0">(</span><span class="sy3">&</span>i,<span class="st0">'c'</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 第 1 个实参:&i -> int* 优于 &i -> const int*</span>
|
|
<span class="co1">// 第 2 个实参:'c' -> int 优于 'c' -> short</span>
|
|
<span class="co1">// 调用 Fcn(int*, int)</span>
|
|
|
|
Fcn<span class="br0">(</span><span class="sy3">&</span>i, s<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 第 1 个实参:&i -> int* 优于 &i -> const int*</span>
|
|
<span class="co1">// 第 2 个实参:s -> short 优于 s -> int</span>
|
|
<span class="co1">// 无胜者,编译错误</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>如果最佳可行函数决议到了一个可以找到多个声明的函数,且这些声明其中的两个存在于不同的作用域并指定了使得该函数可行的默认参数,那么程序非良构。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">namespace</span> A
|
|
<span class="br0">{</span>
|
|
<span class="kw4">extern</span> <span class="st0">"C"</span> <span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span> <span class="sy1">=</span> <span class="nu0">5</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw1">namespace</span> B
|
|
<span class="br0">{</span>
|
|
<span class="kw4">extern</span> <span class="st0">"C"</span> <span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span> <span class="sy1">=</span> <span class="nu0">5</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw1">using</span> A<span class="sy4">::</span><span class="me2">f</span><span class="sy4">;</span>
|
|
<span class="kw1">using</span> B<span class="sy4">::</span><span class="me2">f</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">void</span> use<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
f<span class="br0">(</span><span class="nu0">3</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK,默认实参不会用于使函数可行</span>
|
|
f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误:找到两次默认实参</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E9.9A.90.E5.BC.8F.E8.BD.AC.E6.8D.A2.E5.BA.8F.E5.88.97.E7.9A.84.E6.8E.92.E8.A1.8C">隐式转换序列的排行</span></h3>
|
|
<p>重载决议所考虑的实参-形参隐式转换序列与<a href="cpp-language-copy_initialization.html">复制初始化</a>中(对于非引用形参)所用的<a href="cpp-language-implicit_conversion.html">隐式转换</a>对应,但在到隐含对象形参或到赋值运算符的左侧操作数的转换时不考虑创建临时对象的转换。</p>
|
|
<p>每种<a href="cpp-language-implicit_conversion.html">标准转换序列的类型</a>都被赋予三个等级之一:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> <b>准确匹配</b>:不要求转换、左值到右值转换、限定性转换、<span class="t-rev-inl t-since-cxx17"><span>函数指针转换、</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>类类型到相同类的用户定义转换</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> <b>提升</b>:整型提升、浮点提升</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> <b>转换</b>:整型转换、浮点转换、浮点整型转换、指针转换、成员指针转换、布尔转换、派生类到其基类的用户定义转换</div>
|
|
<p>标准转换序列的等级是其所含的标准转换(至多可有<a href="cpp-language-implicit_conversion.html">三次转换</a>)中的最差等级。</p>
|
|
<p>直接绑定引用形参到实参表达式是恒等或派生类到基类转换:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> Base <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> Derived <span class="sy4">:</span> Base <span class="br0">{</span><span class="br0">}</span> d<span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> f<span class="br0">(</span>Base<span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
|
|
<span class="kw4">int</span> f<span class="br0">(</span>Derived<span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #2</span>
|
|
|
|
<span class="kw4">int</span> i <span class="sy1">=</span> f<span class="br0">(</span>d<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// d -> Derived& 拥有准确匹配等级</span>
|
|
<span class="co1">// d -> Base& 拥有转换等级</span>
|
|
<span class="co1">// 调用 f(Derived&)</span></pre></div>
|
|
</div>
|
|
<p>因为转换序列的排行只会操作类型和值类别,所以就排行而言,<a href="cpp-language-bit_field.html">位域</a>能绑定到引用形参,但如果选择了这个函数,那么程序非良构。</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 标准转换序列始终<i>优于</i>用户定义转换序列或省略号转换序列。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 用户定义转换序列始终<i>优于</i><a href="cpp-language-variadic_arguments.html">省略号转换</a>序列</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 标准转换序列 <code>S1</code> <i>优于</i>标准转换序列 <code>S2</code>,条件为</div>
|
|
<div class="t-li2"><span class="t-li">a)</span> <code>S1</code> 是 <code>S2</code> 的子序列,排除左值变换。恒等转换序列被认为是任何其他转换的子序列;</div>
|
|
<div class="t-li2"><span class="t-li">b)</span> 或若非如此,<code>S1</code> 的等级优于 <code>S2</code> 的等级;</div>
|
|
<div class="t-li2"><span class="t-li">c)</span> 或若非如此,<code>S1</code> 和 <code>S2</code> 都绑定到某个引用形参,而其并非某个引用限定的成员函数的隐式对象形参,且 <code>S1</code> 绑定右值引用到右值而 <code>S2</code> 绑定左值引用到右值
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">int</span> i<span class="sy4">;</span>
|
|
<span class="kw4">int</span> f1<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> g<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">int</span><span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
|
|
<span class="kw4">int</span> g<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">int</span><span class="sy3">&&</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #2</span>
|
|
|
|
<span class="kw4">int</span> j <span class="sy1">=</span> g<span class="br0">(</span>i<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 左值 int -> const int& 是仅有的合法转换</span>
|
|
<span class="kw4">int</span> k <span class="sy1">=</span> g<span class="br0">(</span>f1<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 右值 int -> const int&& 优于 右值 int -> const int&</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li2"><span class="t-li">d)</span> 或若非如此,<code>S1</code> 和 <code>S2</code> 都绑定到引用形参,且 <code>S1</code> 绑定左值引用到函数而 <code>S2</code> 绑定右值引用到函数。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">void</span><span class="br0">(</span><span class="sy3">&</span><span class="br0">)</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
|
|
<span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">void</span><span class="br0">(</span><span class="sy3">&&</span><span class="br0">)</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #2</span>
|
|
|
|
<span class="kw4">void</span> g<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> i1 <span class="sy1">=</span> f<span class="br0">(</span>g<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 #1</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li2"><span class="t-li">e)</span> 或若非如此,<code>S1</code> 和 <code>S2</code> 都绑定到仅在顶层 cv 限定性有别的引用形参,而 <code>S1</code> 的类型比 <code>S2</code> 的 cv 限定性<i>更少</i>。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">int</span> <span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
|
|
<span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">int</span> <span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #2(均为引用)</span>
|
|
<span class="kw4">int</span> g<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">int</span> <span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
|
|
<span class="kw4">int</span> g<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #2</span>
|
|
|
|
<span class="kw4">int</span> i<span class="sy4">;</span>
|
|
<span class="kw4">int</span> j <span class="sy1">=</span> f<span class="br0">(</span>i<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 左值 i -> int& 优于 左值 int -> const int&</span>
|
|
<span class="co1">// 调用 f(int&)</span>
|
|
<span class="kw4">int</span> k <span class="sy1">=</span> g<span class="br0">(</span>i<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 左值 i -> const int& 排行为准确匹配</span>
|
|
<span class="co1">// 左值 i -> 右值 int 排行为准确匹配</span>
|
|
<span class="co1">// 有歧义的重载:编译错误</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li2"><span class="t-li">f)</span> 或若非如此,S1 与 S2 仅在限定性转换有区别,且
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<p><code>S1</code> 的结果的 cv 限定是 <code>S2</code> 的结果的 cv 限定的真子集<span class="t-rev-inl t-until-cxx11"><span>,并且 <code>S1</code> 不是<a href="cpp-language-string_literal.html#.E6.B3.A8.E8.A7.A3">已弃用的字符串字面量数组到指针转换</a></span> <span><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></span></span>。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>能通过限定性转换将 <code>S1</code> 的结果转换为 <code>S2</code> 的结果。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">int</span><span class="sy2">*</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> i<span class="sy4">;</span>
|
|
<span class="kw4">int</span> j <span class="sy1">=</span> f<span class="br0">(</span><span class="sy3">&</span>i<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// &i -> int* 优于 &i -> const int*,调用 f(int*)</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 用户定义转换序列 <code>U1</code> <i>优于</i>用户定义转换序列 <code>U2</code>,如果它们调用相同的构造函数/用户定义转换函数,或以聚合初始化初始化相同的类,而任一情况下 <code>U1</code> 中的第二标准转换序列优于 <code>U2</code> 中的第二标准转换序列:
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span>
|
|
operator <span class="kw4">short</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 用户定义转换函数</span>
|
|
<span class="br0">}</span> a<span class="sy4">;</span>
|
|
<span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
|
|
<span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">float</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #2</span>
|
|
<span class="kw4">int</span> i <span class="sy1">=</span> f<span class="br0">(</span>a<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// A -> short,后随 short -> int(等级为提升)</span>
|
|
<span class="co1">// A -> short,后随 short -> float(等级为转换)</span>
|
|
<span class="co1">// 调用 f(int)</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 列表初始化序列 <code>L1</code> <i>优于</i>列表初始化序列 <code>L2</code>,如果 <code>L1</code> 初始化 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-utility-initializer_list.html"><span class="kw960">std::<span class="me2">initializer_list</span></span></a></span></span> 形参而 <code>L2</code> 没有。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">void</span> f1<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #1</span>
|
|
<span class="kw4">void</span> f1<span class="br0">(</span><a href="cpp-utility-initializer_list.html"><span class="kw960">std::<span class="me2">initializer_list</span></span></a><span class="sy1"><</span><span class="kw4">long</span><span class="sy1">></span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #2</span>
|
|
<span class="kw4">void</span> g1<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> f1<span class="br0">(</span><span class="br0">{</span><span class="nu0">42</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// 选择 #2</span>
|
|
|
|
<span class="kw4">void</span> f2<span class="br0">(</span><a href="cpp-utility-pair.html"><span class="kw1096">std::<span class="me2">pair</span></span></a><span class="sy1"><</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span>, <span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span><span class="sy1">></span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #3</span>
|
|
<span class="kw4">void</span> f2<span class="br0">(</span><a href="cpp-utility-initializer_list.html"><span class="kw960">std::<span class="me2">initializer_list</span></span></a><span class="sy1"><</span><a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a><span class="sy1">></span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #4</span>
|
|
<span class="kw4">void</span> g2<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> f2<span class="br0">(</span><span class="br0">{</span><span class="st0">"foo"</span>,<span class="st0">"bar"</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// 选择 #4</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11 t-until-cxx20">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">6)</span> 列表初始化序列 <code>L1</code> <i>优于</i>列表初始化序列 <code>L2</code> ,如果对应形参是到数组的引用且 L1 转换到“N1 个 T 的数组”,L2 转换到“N2 个 T 的数组”,而 N1 小于 N2。</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span><br />
|
|
<span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">6)</span> 列表初始化序列 <code>L1</code> <i>优于</i>列表初始化序列 <code>L2</code> ,如果 L1 与 L2 均转换到相同元素类型的数组,且
|
|
<ul>
|
|
<li>L1 所初始化的元素数 N1 小于 L2 所初始化的元素数 N2 ,或</li>
|
|
<li>N1 等于 N2 ,但 L2 转换到未知边界数组而 L1 没有。</li>
|
|
</ul>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span> <span class="br0">(</span><span class="sy3">&&</span><span class="br0">)</span><span class="br0">[</span><span class="br0">]</span> <span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #1</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">double</span> <span class="br0">(</span><span class="sy3">&&</span><span class="br0">)</span><span class="br0">[</span><span class="br0">]</span> <span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #2</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span> <span class="br0">(</span><span class="sy3">&&</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 重载 #3</span>
|
|
|
|
f<span class="br0">(</span><span class="br0">{</span><span class="nu0">1</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #1:由于转换优于 #2 ,由于边界优于 #3</span>
|
|
f<span class="br0">(</span><span class="br0">{</span><span class="nu16">1.0</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #2:double -> double 优于 double -> int</span>
|
|
f<span class="br0">(</span><span class="br0">{</span><span class="nu16">1.0</span>, <span class="nu16">2.0</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #2:double -> double 优于 double -> int</span>
|
|
f<span class="br0">(</span><span class="br0">{</span><span class="nu0">1</span>, <span class="nu0">2</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #3:-> int[2] 优于 -> int[] , </span>
|
|
<span class="co1">// 而 int -> int 优于 int -> double</span></pre></div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>如果两个转换序列因为拥有相同等级而不可辨别,那么则应用下列额外规则:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 涉及指针到 bool 或成员指针到 bool 的转换劣于不涉及这些的转换。</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">2)</span> 如果底层类型固定的<a href="cpp-language-enum.html">枚举</a>的底层类型与经提升后的底层类型不同,则提升到其底层类型的转换优于提升到提升后底层类型的转换。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw2">enum</span> num <span class="sy4">:</span> <span class="kw4">char</span> <span class="br0">{</span> one <span class="sy1">=</span> <span class="st0">'0'</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> num<span class="sy4">::</span><span class="me2">one</span><span class="sy4">;</span> <span class="co1">// '0',而不是 48</span></pre></div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">3)</span> 派生类指针到基类指针的转换优于派生类指针到 void 指针的转换,而基类指针到 void 的转换优于派生类指针到 void 指针的转换。</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 如果 <code>Mid</code>(直接或间接)从 <code>Base</code> 派生,而 <code>Derived</code>(直接或间接)从 <code>Mid</code>派生,那么</div>
|
|
<div class="t-li2"><span class="t-li">a)</span> <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived<span class="sy2">*</span></span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Mid<span class="sy2">*</span></span></span> 优于 <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived<span class="sy2">*</span></span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy2">*</span></span></span></div>
|
|
<div class="t-li2"><span class="t-li">b)</span> <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived</span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Mid<span class="sy3">&</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp">Mid<span class="sy3">&&</span></span></span> 优于 <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived</span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy3">&</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy3">&&</span></span></span></div>
|
|
<div class="t-li2"><span class="t-li">c)</span> <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy4">::</span><span class="sy2">*</span></span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Mid<span class="sy4">::</span><span class="sy2">*</span></span></span> 优于 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy4">::</span><span class="sy2">*</span></span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived<span class="sy4">::</span><span class="sy2">*</span></span></span></div>
|
|
<div class="t-li2"><span class="t-li">d)</span> <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived</span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Mid</span></span> 优于 <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived</span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base</span></span></div>
|
|
<div class="t-li2"><span class="t-li">e)</span> <span class="t-c"><span class="mw-geshi cpp source-cpp">Mid<span class="sy2">*</span></span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy2">*</span></span></span> 优于 <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived<span class="sy2">*</span></span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy2">*</span></span></span></div>
|
|
<div class="t-li2"><span class="t-li">f)</span> <span class="t-c"><span class="mw-geshi cpp source-cpp">Mid</span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy3">&</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy3">&&</span></span></span> 优于 <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived</span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy3">&</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy3">&&</span></span></span></div>
|
|
<div class="t-li2"><span class="t-li">g)</span> <span class="t-c"><span class="mw-geshi cpp source-cpp">Mid<span class="sy4">::</span><span class="sy2">*</span></span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived<span class="sy4">::</span><span class="sy2">*</span></span></span> 优于 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base<span class="sy4">::</span><span class="sy2">*</span></span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived<span class="sy4">::</span><span class="sy2">*</span></span></span></div>
|
|
<div class="t-li2"><span class="t-li">h)</span> <span class="t-c"><span class="mw-geshi cpp source-cpp">Mid</span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base</span></span> 优于 <span class="t-c"><span class="mw-geshi cpp source-cpp">Derived</span></span> 到 <span class="t-c"><span class="mw-geshi cpp source-cpp">Base</span></span></div>
|
|
<p>对有歧义的转换序列的分级与用户定义转换序列相同,因为一个实参的多个转换序列只有在它们涉及不同的用户定义转换时才能存在:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">class</span> B<span class="sy4">;</span>
|
|
<span class="kw1">class</span> A <span class="br0">{</span> A <span class="br0">(</span>B<span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 转换构造函数</span>
|
|
<span class="kw1">class</span> B <span class="br0">{</span> operator A <span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 用户定义转换函数</span>
|
|
<span class="kw1">class</span> C <span class="br0">{</span> C <span class="br0">(</span>B<span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 转换构造函数</span>
|
|
|
|
<span class="kw4">void</span> f<span class="br0">(</span>A<span class="br0">)</span> <span class="br0">{</span> <span class="br0">}</span> <span class="co1">// 重载 #1</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>C<span class="br0">)</span> <span class="br0">{</span> <span class="br0">}</span> <span class="co1">// 重载 #2</span>
|
|
|
|
B b<span class="sy4">;</span>
|
|
f<span class="br0">(</span>b<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// B -> A 经由构造函数或 B -> A 经由函数(有歧义转换)</span>
|
|
<span class="co1">// b -> C 经由构造函数(用户定义转换)</span>
|
|
<span class="co1">// 重载 #1 和 #2 的转换无法辨别;编译失败</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.88.97.E8.A1.A8.E5.88.9D.E5.A7.8B.E5.8C.96.E4.B8.AD.E7.9A.84.E9.9A.90.E5.BC.8F.E8.BD.AC.E6.8D.A2.E5.BA.8F.E5.88.97">列表初始化中的隐式转换序列</span></h3>
|
|
<p>在<a href="cpp-language-list_initialization.html">列表初始化</a>中,实参是 <span class="t-spar">花括号初始化器列表</span>,但它不是表达式,所以到就重载决议而言的形参类型的隐式转换序列以下列规则决定:</p>
|
|
<ul>
|
|
<li>如果形参类型是某聚合体 <code>X</code> 且初始化器列表确切地由一个同类型或其派生类(可有 cv 限定)的元素组成,那么隐式转换序列是将该元素转换到形参类型所要求的序列。</li>
|
|
<li>否则,如果形参类型是到字符数组的引用且初始化器列表拥有单个元素,元素为类型适当的字符串字面量,那么隐式转换序列为恒等转换。</li>
|
|
<li>否则,如果形参类型是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-utility-initializer_list.html"><span class="kw960">std::<span class="me2">initializer_list</span></span></a><span class="sy1"><</span>X<span class="sy1">></span></span></span> 且存在从每个初始化器列表元素到 <code>X</code> 的非窄化隐式转换,那么就重载决议而言的隐式转换序列是所需的最坏转换。如果 <span class="t-spar">花括号初始化器列表</span> 为空,那么转换序列为恒等转换。</li>
|
|
</ul>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A
|
|
<span class="br0">{</span>
|
|
A<span class="br0">(</span><a href="cpp-utility-initializer_list.html"><span class="kw960">std::<span class="me2">initializer_list</span></span></a><span class="sy1"><</span><span class="kw4">double</span><span class="sy1">></span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #1</span>
|
|
A<span class="br0">(</span><a href="cpp-utility-initializer_list.html"><span class="kw960">std::<span class="me2">initializer_list</span></span></a><span class="sy1"><</span>complex<span class="sy1"><</span><span class="kw4">double</span><span class="sy1">>></span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #2</span>
|
|
A<span class="br0">(</span><a href="cpp-utility-initializer_list.html"><span class="kw960">std::<span class="me2">initializer_list</span></span></a><span class="sy1"><</span><a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a><span class="sy1">></span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #3</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
A a<span class="br0">{</span><span class="nu16">1.0</span>,<span class="nu16">2.0</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 选择 #1(右值 double -> double:恒等转换)</span>
|
|
|
|
<span class="kw4">void</span> g<span class="br0">(</span>A<span class="br0">)</span><span class="sy4">;</span>
|
|
g<span class="br0">(</span><span class="br0">{</span><span class="st0">"foo"</span>,<span class="st0">"bar"</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 选择 #3(左值 const char[4] -> std::string:用户定义转换)</span></pre></div>
|
|
</div>
|
|
<ul>
|
|
<li>否则,如果形参类型是“ N 个 T 的数组”(这只对到数组的引用发生),那么初始化器列表必须有 N 个或更少的元素,且所用的隐式转换序列是将列表(或空花括号对,如果 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="br0">{</span><span class="br0">}</span></span></span> 小于 N)的每个元素转换到 <code>T</code> 所需的最坏隐式转换序列。</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<ul>
|
|
<li>否则,如果形参类型是“ T 的未知边界数组”(这只对到数组的引用发生),那么所用的隐式转换序列是将列表的每个元素转换到 <code>T</code> 所需的最坏隐式转换序列。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">typedef</span> <span class="kw4">int</span> IA<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> h<span class="br0">(</span><span class="kw4">const</span> IA<span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> g<span class="br0">(</span><span class="kw4">int</span> <span class="br0">(</span><span class="sy3">&&</span><span class="br0">)</span><span class="br0">[</span><span class="br0">]</span><span class="br0">)</span>
|
|
|
|
h<span class="br0">(</span><span class="br0">{</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// int -> int 恒等转换</span>
|
|
g<span class="br0">(</span><span class="br0">{</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// C++20 起同上</span></pre></div>
|
|
</div>
|
|
<ul>
|
|
<li>否则,如果形参类型为非聚合类类型 <code>X</code>,那么重载决议选取 X 的构造函数 C 以从实参初始化器列表初始化</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>如果 C 是非 initializer_list 构造函数且而该初始化器列表拥有单个元素,其类型为可为 cv 限定的 X,那么隐式转换序列具有准确匹配等级。如果该初始化器列表拥有单个元素,其具有可有 cv 限定的派生自 X 的类型,那么隐式转换序列具有转换等级。(注意它和聚合体的区别:聚合体在考虑<a href="cpp-language-aggregate_initialization.html">聚合初始化</a>前直接从单元素初始化器列表进行初始化,而非聚合体在考虑任何其他构造函数之前先考虑 initializer_list 构造函数)</li>
|
|
<li>否则,隐式转换序列是以恒等转换为第二标准转换序列的用户定义转换序列。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<p>如果有多个构造函数可行,但是没有一个优于其他所有构造函数,那么隐式转换序列是有歧义的转换序列。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span> A<span class="br0">(</span><a href="cpp-utility-initializer_list.html"><span class="kw960">std::<span class="me2">initializer_list</span></span></a><span class="sy1"><</span><span class="kw4">int</span><span class="sy1">></span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>A<span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
<span class="kw1">struct</span> B <span class="br0">{</span> B<span class="br0">(</span><span class="kw4">int</span>, <span class="kw4">double</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> g<span class="br0">(</span>B<span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
g<span class="br0">(</span><span class="br0">{</span><span class="st0">'a'</span>,<span class="st0">'b'</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 g(B(int,double)),用户定义转换</span>
|
|
<span class="co1">// g({1.0, 1,0}); // 错误:double->int 为窄化,在列表初始化中不允许</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>B<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// f({'a','b'}); // f(A) 与 f(B) 均为用户定义转换</span></pre></div>
|
|
</div>
|
|
<ul>
|
|
<li>否则,如果形参类型是可按照<a href="cpp-language-aggregate_initialization.html">聚合初始化</a>从初始化器列表初始化的聚合体,那么隐式转换序列是以恒等转换为第二标准转换序列的用户定义转换序列:</li>
|
|
</ul>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span> <span class="kw4">int</span> m1<span class="sy4">;</span> <span class="kw4">double</span> m2<span class="sy4">;</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>A<span class="br0">)</span><span class="sy4">;</span>
|
|
f<span class="br0">(</span><span class="br0">{</span><span class="st0">'a'</span>,<span class="st0">'b'</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 f(A(int,double)),用户定义转换</span></pre></div>
|
|
</div>
|
|
<ul>
|
|
<li>否则,如果形参是引用,那么应用引用初始化规则:</li>
|
|
</ul>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span> <span class="kw4">int</span> m1<span class="sy4">;</span> <span class="kw4">double</span> m2<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">const</span> A<span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span>
|
|
f<span class="br0">(</span><span class="br0">{</span><span class="st0">'a'</span>,<span class="st0">'b'</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 创建临时量,调用 f(A(int,double))。用户定义转换</span></pre></div>
|
|
</div>
|
|
<ul>
|
|
<li>否则,如果形参类型不是类且初始化器列表拥有一个元素,那么隐式转换序列为将该元素转换到形参类型所要求者。</li>
|
|
<li>否则,如果形参类型不是类且初始化器列表没有元素,那么隐式转换序列为恒等转换。</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>如果实参是指派初始化器列表,那么只有在形参拥有聚合类型且该类型能按照<a href="cpp-language-aggregate_initialization.html">聚合初始化</a>的规则从初始化器列表初始化时,转换才可行。此时隐式转换序列是以恒等转换为第二标准转换序列的用户定义转换序列。</p>
|
|
<p>如果在重载决议后,聚合体各成员的声明顺序与所选择的重载不匹配,那么形参的初始化将为非良构。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span> <span class="kw4">int</span> x, y<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> B <span class="br0">{</span> <span class="kw4">int</span> y, x<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">void</span> f<span class="br0">(</span>A a, <span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #1</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span>B b, ...<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #2</span>
|
|
<span class="kw4">void</span> g<span class="br0">(</span>A a<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #3</span>
|
|
<span class="kw4">void</span> g<span class="br0">(</span>B b<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// #4</span>
|
|
|
|
<span class="kw4">void</span> h<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
f<span class="br0">(</span><span class="br0">{</span>.<span class="me1">x</span> <span class="sy1">=</span> <span class="nu0">1</span>, .<span class="me1">y</span> <span class="sy1">=</span> <span class="nu0">2</span><span class="br0">}</span>, <span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK:调用 #1</span>
|
|
f<span class="br0">(</span><span class="br0">{</span>.<span class="me1">y</span> <span class="sy1">=</span> <span class="nu0">2</span>, .<span class="me1">x</span> <span class="sy1">=</span> <span class="nu0">1</span><span class="br0">}</span>, <span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误:选择 #1,初始化由于不匹配的成员顺序失败</span>
|
|
g<span class="br0">(</span><span class="br0">{</span>.<span class="me1">x</span> <span class="sy1">=</span> <span class="nu0">1</span>, .<span class="me1">y</span> <span class="sy1">=</span> <span class="nu0">2</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误:在 #3 和 #4 间有歧义</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p><br /></p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<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/issue1">CWG 1</a></td>
|
|
<td>C++98</td>
|
|
<td>选择可能有(来自不同作用域的)不同默认实参的相同函数时的行为未指明</td>
|
|
<td>此时程序非良构</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue83">CWG 83</a></td>
|
|
<td>C++98</td>
|
|
<td>从字符串字面量到 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">char</span><span class="sy2">*</span></span></span> 的转换序列优于<br />
|
|
到 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span></span></span> 的转换序列,即使前者已弃用</td>
|
|
<td>降低该已弃用的转换序列的排行<br />
|
|
(该隐式转换已在 C++11 移除)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1307">CWG 1307</a></td>
|
|
<td>C++11</td>
|
|
<td>未指定基于数组大小的重载决议</td>
|
|
<td>可能时较短的数组较好</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1601">CWG 1601</a></td>
|
|
<td>C++11</td>
|
|
<td>从 enum 转换到其底层类型不偏好固定的底层类型</td>
|
|
<td>底层类型比提升后的该类型更受偏好</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1467">CWG 1467</a></td>
|
|
<td>C++11</td>
|
|
<td>略去了聚合体和数组的同类型列表初始化</td>
|
|
<td>定义这种初始化</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue2137">CWG 2137</a></td>
|
|
<td>C++11</td>
|
|
<td>从 {X} 列表初始化 X 时,初始化器列表构造函数输给复制构造函数</td>
|
|
<td>非聚合体首先考虑初始化器列表</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E5.BC.95.E7.94.A8">引用</span></h3>
|
|
<div class="t-ref-std-c++20">
|
|
<ul>
|
|
<li>C++20 标准(ISO/IEC 14882:2020):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>12.4 Overload resolution [over.match]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c++17">
|
|
<ul>
|
|
<li>C++17 标准(ISO/IEC 14882:2017):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>16.3 Overload resolution [over.match]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c++14">
|
|
<ul>
|
|
<li>C++14 标准(ISO/IEC 14882:2014):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>13.3 Overload resolution [over.match]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c++11">
|
|
<ul>
|
|
<li>C++11 标准(ISO/IEC 14882:2011):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>13.3 Overload resolution [over.match]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c++03">
|
|
<ul>
|
|
<li>C++03 标准(ISO/IEC 14882:2003):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>13.3 Overload resolution [over.match]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<ul>
|
|
<li><a href="cpp-language-lookup.html">名字查找</a></li>
|
|
<li><a href="cpp-language-adl.html">实参依赖查找</a></li>
|
|
<li><a href="cpp-language-template_argument_deduction.html">模板实参推导</a></li>
|
|
<li><a href="cpp-language-sfinae.html">SFINAE</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|