250 lines
56 KiB
HTML
250 lines
56 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_value_category 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>每个 C++ <a href="cpp-language-expressions.html">表达式</a>(带有操作数的操作符、字面量、变量名等)可按照两种独立的特性加以辨别:<i>类型</i>和<i>值类别 (value category)</i>。每个表达式都具有某种非引用类型,且每个表达式只属于三种基本值类别中的一种:<i>纯右值 (prvalue)</i>、<i>亡值 (xvalue)</i>、<i>左值 (lvalue)</i>。</p>
|
|
<ul>
|
|
<li><b>泛左值 (glvalue)</b>(“泛化 (generalized)”的左值)是其求值确定一个对象、位域或函数的个体的表达式;</li>
|
|
<li><b>纯右值 (prvalue)</b>(“纯 (pure)”的右值)是求值符合下列之一的表达式:
|
|
<ul>
|
|
<li>计算某个运算符的操作数的值或为 void 表达式(这种纯右值没有<i>结果对象</i>)</li>
|
|
<li>初始化某个对象或位域(称这种纯右值有一个<i>结果对象</i>)。除 <a href="cpp-language-decltype.html">decltype</a> 外,所有类和数组的纯右值都有结果对象,即使它被舍弃也是如此。结果对象可以是变量,由 <a href="cpp-language-new.html">new 表达式</a>创建的对象,由<a href="cpp-language-implicit_conversion.html#.E4.B8.B4.E6.97.B6.E9.87.8F.E5.AE.9E.E8.B4.A8.E5.8C.96">临时量实质化</a>创建的临时对象,或者前述三类对象的成员;</li>
|
|
</ul>
|
|
</li>
|
|
<li><b>亡值 (xvalue)</b>(“将亡 (expiring)”的值)是代表其资源能够被重新使用的对象或位域的泛左值;</li>
|
|
<li><b>左值 (lvalue)</b>(如此称呼的历史原因是,左值可以出现于赋值表达式的左边)是非亡值的泛左值;</li>
|
|
<li><b>右值 (rvalue)</b>(如此称呼的历史原因是,右值可以出现于赋值表达式的右边)是纯右值或者亡值。</li>
|
|
</ul>
|
|
<p>注意:这个分类法与 C++ 标准过去的各版本相比经历了显著变更,详见下文的<a href="cpp-language-value_category.html#.E5.8E.86.E5.8F.B2">历史</a>部分。</p>
|
|
<h3><span class="mw-headline" id=".E5.9F.BA.E6.9C.AC.E7.B1.BB.E5.88.AB">基本类别</span></h3>
|
|
<h4><span class="mw-headline" id=".E5.B7.A6.E5.80.BC">左值</span></h4>
|
|
<p>下列表达式是<i>左值表达式</i>:</p>
|
|
<ul>
|
|
<li>变量、函数<span class="t-rev-inl t-since-cxx20"><span>、<a href="cpp-language-template_parameters.html#.E9.9D.9E.E7.B1.BB.E5.9E.8B.E6.A8.A1.E6.9D.BF.E5.BD.A2.E5.8F.82">模板形参对象</a></span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>或数据成员的名字,不论其类型,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-io-cin.html"><span class="kw1756">std::<span class="me2">cin</span></span></a></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-io-manip-endl.html"><span class="kw1791">std::<span class="me2">endl</span></span></a></span></span>。即使变量的类型是右值引用,由其名字构成的表达式仍是左值表达式;</li>
|
|
<li>返回类型为左值引用的函数调用或重载运算符表达式,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-string-basic_string-getline.html"><span class="kw1256">std::<span class="me2">getline</span></span></a><span class="br0">(</span><a href="cpp-io-cin.html"><span class="kw1756">std::<span class="me2">cin</span></span></a>, str<span class="br0">)</span></span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="nu0">1</span></span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp">str1 <span class="sy1">=</span> str2</span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">++</span>it</span></span>;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy1">=</span> b</span></span>,<span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy2">+</span><span class="sy1">=</span> b</span></span>,<span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy2">%</span><span class="sy1">=</span> b</span></span>,以及所有其他内建的<a href="cpp-language-operator_assignment.html">赋值及复合赋值</a>表达式;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">++</span>a</span></span> 和 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">--</span>a</span></span>,内建的<a href="cpp-language-operator_incdec.html#.E5.86.85.E5.BB.BA.E7.9A.84.E5.89.8D.E7.BD.AE.E8.BF.90.E7.AE.97.E7.AC.A6">前置自增与前置自减</a>表达式;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">*</span>p</span></span>,内建的<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E9.97.B4.E6.8E.A5.E5.AF.BB.E5.9D.80.E8.BF.90.E7.AE.97.E7.AC.A6">间接寻址</a>表达式;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a<span class="br0">[</span>n<span class="br0">]</span></span></span> 和 <span class="t-c"><span class="mw-geshi cpp source-cpp">n<span class="br0">[</span>a<span class="br0">]</span></span></span>,内建的<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E4.B8.8B.E6.A0.87.E8.BF.90.E7.AE.97.E7.AC.A6">下标</a>表达式<span class="t-rev-inl t-since-cxx11"><span>,当 <code>a[n]</code> 中的一个操作数为数组左值时</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a.<span class="me1">m</span></span></span>,<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>表达式,除了 <code>m</code> 为成员枚举项或非静态成员函数,或者 <code>a</code> 为右值而 <code>m</code> 为对象类型的非静态数据成员的情况;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">p<span class="sy2">-</span><span class="sy1">></span>m</span></span>,内建的<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>表达式,除了 <code>m</code> 为成员枚举项或非静态成员函数的情况;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a.<span class="sy2">*</span>mp</span></span>,<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E6.88.90.E5.91.98.E6.8C.87.E9.92.88.E8.AE.BF.E9.97.AE.E8.BF.90.E7.AE.97.E7.AC.A6">对象的成员指针</a>表达式,其中 <code>a</code> 是左值且 <code>mp</code> 是数据成员指针;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">p<span class="sy2">-</span><span class="sy1">></span><span class="sy2">*</span>mp</span></span>,内建的<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E6.88.90.E5.91.98.E6.8C.87.E9.92.88.E8.AE.BF.E9.97.AE.E8.BF.90.E7.AE.97.E7.AC.A6">指针的成员指针</a>表达式,其中 <code>mp</code> 是数据成员指针;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a, b</span></span>,内建的<a href="cpp-language-operator_other.html#.E5.86.85.E5.BB.BA.E7.9A.84.E9.80.97.E5.8F.B7.E8.BF.90.E7.AE.97.E7.AC.A6">逗号</a>表达式,其中 <code>b</code> 是左值;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy4">?</span> b <span class="sy4">:</span> c</span></span>,对某些 <code>b</code> 和 <code>c</code> 的<a href="cpp-language-operator_other.html#.E6.9D.A1.E4.BB.B6.E8.BF.90.E7.AE.97.E7.AC.A6">三元条件</a>表达式(例如,当它们都是同类型左值时,但细节见其<a href="cpp-language-operator_other.html#.E6.9D.A1.E4.BB.B6.E8.BF.90.E7.AE.97.E7.AC.A6">定义</a>);</li>
|
|
<li><a href="cpp-language-string_literal.html">字符串字面量</a>,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="st0">"Hello, world!"</span></span></span>;</li>
|
|
<li>转换为左值引用类型的转型表达式,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">static_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="sy3">&</span><span class="sy1">></span><span class="br0">(</span>x<span class="br0">)</span></span></span>;</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li>返回类型是到函数的右值引用的函数调用表达式或重载的运算符表达式;</li>
|
|
<li>转换为函数的右值引用类型的转型表达式,如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">static_cast</span><span class="sy1"><</span><span class="kw4">void</span> <span class="br0">(</span><span class="sy3">&&</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy1">></span><span class="br0">(</span>x<span class="br0">)</span></span></span>。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>性质:</p>
|
|
<ul>
|
|
<li>与泛左值相同(见下文)。</li>
|
|
<li>可以由内建的取址运算符取左值的地址:<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">&</span><span class="sy2">++</span>i</span></span><sup id="cite_ref-1" class="reference"><a href="cpp-language-value_category.html#cite_note-1">[1]</a></sup> 及 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">&</span><a href="cpp-io-manip-endl.html"><span class="kw1791">std::<span class="me2">endl</span></span></a></span></span> 是合法表达式。</li>
|
|
<li>可修改的左值可用作内建赋值和内建复合赋值运算符的左操作数。</li>
|
|
<li>左值可用于<a href="cpp-language-reference_initialization.html">初始化左值引用</a>;这会将一个新名字关联给该表达式所标识的对象。</li>
|
|
</ul>
|
|
<h4><span class="mw-headline" id=".E7.BA.AF.E5.8F.B3.E5.80.BC">纯右值</span></h4>
|
|
<p>下列表达式是<i>纯右值表达式</i>:</p>
|
|
<ul>
|
|
<li>(除了<a href="cpp-language-string_literal.html">字符串字面量</a>之外的)<a href="cpp-language-expressions.html#.E5.AD.97.E9.9D.A2.E9.87.8F">字面量</a>,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="nu0">42</span></span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw2">true</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp">nullptr</span></span>;</li>
|
|
<li>返回类型是非引用的函数调用或重载运算符表达式,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp">str.<span class="me1">substr</span><span class="br0">(</span><span class="nu0">1</span>, <span class="nu0">2</span><span class="br0">)</span></span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp">str1 <span class="sy2">+</span> str2</span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp">it<span class="sy2">++</span></span></span>;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a<span class="sy2">++</span></span></span> 和 <span class="t-c"><span class="mw-geshi cpp source-cpp">a<span class="sy2">--</span></span></span>,内建的<a href="cpp-language-operator_incdec.html#.E5.86.85.E5.BB.BA.E7.9A.84.E5.90.8E.E7.BD.AE.E8.BF.90.E7.AE.97.E7.AC.A6">后置自增与后置自减</a>表达式;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy2">+</span> b</span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy2">%</span> b</span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy3">&</span> b</span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy1"><<</span> b</span></span>,以及其他所有内建的<a href="cpp-language-operator_arithmetic.html">算术</a>表达式;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy3">&&</span> b</span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy3">||</span> b</span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">!</span>a</span></span>,内建的<a href="cpp-language-operator_logical.html">逻辑</a>表达式;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy1"><</span> b</span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy1">==</span> b</span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy1">>=</span> b</span></span> 以及其他所有内建的<a href="cpp-language-operator_comparison.html">比较</a>表达式;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">&</span>a</span></span>,内建的<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E5.8F.96.E5.9C.B0.E5.9D.80.E8.BF.90.E7.AE.97.E7.AC.A6">取地址</a>表达式;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a.<span class="me1">m</span></span></span>,<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>表达式,其中 <code>m</code> 是成员枚举项或非静态成员函数<sup id="cite_ref-pmfc_2-0" class="reference"><a href="cpp-language-value_category.html#cite_note-pmfc-2">[2]</a></sup><span class="t-rev-inl t-until-cxx11"><span>,或其中 <code>a</code> 为右值且 <code>m</code> 为非引用类型的非静态数据成员</span> <span><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></span></span>;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">p<span class="sy2">-</span><span class="sy1">></span>m</span></span>,内建的<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>表达式,其中 <code>m</code> 为成员枚举项或非静态成员函数<sup id="cite_ref-pmfc_2-1" class="reference"><a href="cpp-language-value_category.html#cite_note-pmfc-2">[2]</a></sup>;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a.<span class="sy2">*</span>mp</span></span>,<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E6.88.90.E5.91.98.E6.8C.87.E9.92.88.E8.AE.BF.E9.97.AE.E8.BF.90.E7.AE.97.E7.AC.A6">对象的成员指针</a>表达式,其中 <code>mp</code> 是成员函数指针<sup id="cite_ref-pmfc_2-2" class="reference"><a href="cpp-language-value_category.html#cite_note-pmfc-2">[2]</a></sup><span class="t-rev-inl t-until-cxx11"><span>,或其中 <code>a</code> 为右值且 <code>mp</code> 为数据成员指针</span> <span><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></span></span>;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">p<span class="sy2">-</span><span class="sy1">></span><span class="sy2">*</span>mp</span></span>,内建的<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E6.88.90.E5.91.98.E6.8C.87.E9.92.88.E8.AE.BF.E9.97.AE.E8.BF.90.E7.AE.97.E7.AC.A6">指针的成员指针</a>表达式,其中 <code>mp</code> 是成员函数指针<sup id="cite_ref-pmfc_2-3" class="reference"><a href="cpp-language-value_category.html#cite_note-pmfc-2">[2]</a></sup>;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a, b</span></span>,内建的<a href="cpp-language-operator_other.html#.E5.86.85.E5.BB.BA.E7.9A.84.E9.80.97.E5.8F.B7.E8.A1.A8.E8.BE.BE.E5.BC.8F">逗号</a>表达式,其中 <code>b</code> 是右值;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy4">?</span> b <span class="sy4">:</span> c</span></span>,对某些 <code>b</code> 和 <code>c</code> 的<a href="cpp-language-operator_other.html#.E6.9D.A1.E4.BB.B6.E8.BF.90.E7.AE.97.E7.AC.A6">三元条件</a>表达式(细节见其<a href="cpp-language-operator_other.html#.E6.9D.A1.E4.BB.B6.E8.BF.90.E7.AE.97.E7.AC.A6">定义</a>);</li>
|
|
<li>转换为非引用类型的转型表达式,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">static_cast</span><span class="sy1"><</span><span class="kw4">double</span><span class="sy1">></span><span class="br0">(</span>x<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 class="br0">{</span><span class="br0">}</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="nu0">42</span></span></span>;</li>
|
|
<li><a href="cpp-language-this.html"><code>this</code></a> 指针;</li>
|
|
<li><a href="cpp-language-enum.html">枚举项</a>;</li>
|
|
<li>非类型<a href="cpp-language-template_parameters.html">模板形参</a>,除非其类型为<span class="t-rev-inl t-since-cxx20"><span>类或</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>左值引用类型;</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li><a href="cpp-language-lambda.html">lambda 表达式</a>,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">int</span> x<span class="br0">)</span><span class="br0">{</span> <span class="kw1">return</span> x <span class="sy2">*</span> x<span class="sy4">;</span> <span class="br0">}</span></span></span>;</li>
|
|
</ul>
|
|
</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>
|
|
<ul>
|
|
<li><a href="cpp-language-constraints.html">requires 表达式</a>,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp">requires <span class="br0">(</span>T i<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">typename</span> T<span class="sy4">::</span><span class="me2">type</span><span class="sy4">;</span> <span class="br0">}</span></span></span>;</li>
|
|
<li><a href="cpp-language-constraints.html">概念</a>的特化,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp">std<span class="sy4">::</span><span class="me2">equality_comparable</span><span class="sy1"><</span><span class="kw4">int</span><span class="sy1">></span></span></span>。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>性质:</p>
|
|
<ul>
|
|
<li>与右值相同(见下文)。</li>
|
|
<li>纯右值不具有<a href="cpp-language-object.html#.E5.A4.9A.E6.80.81.E5.AF.B9.E8.B1.A1">多态</a>:它所标识的对象的<a href="cpp-language-types.html#.E5.8A.A8.E6.80.81.E7.B1.BB.E5.9E.8B">动态类型</a>始终为该表达式的类型。</li>
|
|
<li>非类非数组的纯右值不能有 <a href="cpp-language-cv.html">cv 限定</a><span class="t-rev-inl t-since-cxx17"><span>,除非它被<a href="cpp-language-implicit_conversion.html#.E4.B8.B4.E6.97.B6.E9.87.8F.E5.AE.9E.E8.B4.A8.E5.8C.96">实质化</a>以<a href="cpp-language-reference_initialization.html">绑定</a>到 cv 限定类型的引用</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>。(注意:函数调用或转型表达式可能生成非类的 cv 限定类型的纯右值,但其 cv 限定符通常被立即剥除。)</li>
|
|
<li>纯右值不能具有<a href="cpp-language-type.html#.E4.B8.8D.E5.AE.8C.E6.95.B4.E7.B1.BB.E5.9E.8B">不完整类型</a>(除了类型 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">void</span></span></span>(见下文),或在 <a href="cpp-language-decltype.html"><code>decltype</code> 说明符</a>中使用之外)</li>
|
|
<li>纯右值不能具有<a href="cpp-language-abstract_class.html">抽象类类型</a>或其数组类型。</li>
|
|
</ul>
|
|
<h4><span class="mw-headline" id=".E4.BA.A1.E5.80.BC">亡值</span></h4>
|
|
<p>下列表达式是<i>亡值表达式</i>:</p>
|
|
<ul>
|
|
<li>返回类型为对象的右值引用的函数调用或重载运算符表达式,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp">std<span class="sy4">::</span><span class="me2">move</span><span class="br0">(</span>x<span class="br0">)</span></span></span>;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a<span class="br0">[</span>n<span class="br0">]</span></span></span>,内建的<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E4.B8.8B.E6.A0.87.E8.BF.90.E7.AE.97.E7.AC.A6">下标</a>表达式,其操作数之一是数组右值;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a.<span class="me1">m</span></span></span>,<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>表达式,其中 <code>a</code> 是右值且 <code>m</code> 是非引用类型的非静态数据成员;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a.<span class="sy2">*</span>mp</span></span>,<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E6.88.90.E5.91.98.E6.8C.87.E9.92.88.E8.AE.BF.E9.97.AE.E8.BF.90.E7.AE.97.E7.AC.A6">对象的成员指针</a>表达式,其中 <code>a</code> 为右值且 <code>mp</code> 为数据成员指针;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy4">?</span> b <span class="sy4">:</span> c</span></span>,对某些 <code>b</code> 和 <code>c</code> 的<a href="cpp-language-operator_other.html#.E6.9D.A1.E4.BB.B6.E8.BF.90.E7.AE.97.E7.AC.A6">三元条件</a>表达式(细节见其<a href="cpp-language-operator_other.html#.E6.9D.A1.E4.BB.B6.E8.BF.90.E7.AE.97.E7.AC.A6">定义</a>);</li>
|
|
<li>转换为对象的右值引用类型的转型表达式,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">static_cast</span><span class="sy1"><</span><span class="kw4">char</span><span class="sy3">&&</span><span class="sy1">></span><span class="br0">(</span>x<span class="br0">)</span></span></span>;</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx17">
|
|
<td>
|
|
<ul>
|
|
<li>在<a href="cpp-language-implicit_conversion.html#.E4.B8.B4.E6.97.B6.E9.87.8F.E5.AE.9E.E8.B4.A8.E5.8C.96">临时量实质化</a>后,任何指代该临时对象的表达式。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>性质:</p>
|
|
<ul>
|
|
<li>与右值相同(见下文)。</li>
|
|
<li>与泛左值相同(见下文)。</li>
|
|
</ul>
|
|
<p>特别是,与所有的右值类似,亡值可以绑定到右值引用上,而且与所有的泛左值类似,亡值可以是<a href="cpp-language-object.html#.E5.A4.9A.E6.80.81.E5.AF.B9.E8.B1.A1">多态的</a>,而且非类的亡值可以有 <a href="cpp-language-cv.html">cv 限定</a>。</p>
|
|
<h3><span class="mw-headline" id=".E6.B7.B7.E5.90.88.E7.B1.BB.E5.88.AB">混合类别</span></h3>
|
|
<h4><span class="mw-headline" id=".E6.B3.9B.E5.B7.A6.E5.80.BC">泛左值</span></h4>
|
|
<p><i>泛左值</i>表达式包括左值、亡值。</p>
|
|
<p>性质:</p>
|
|
<ul>
|
|
<li>泛左值可以通过左值到右值、数组到指针或函数到指针<a href="cpp-language-implicit_conversion.html">隐式转换</a>转换成纯右值。</li>
|
|
<li>泛左值可以是<a href="cpp-language-object.html#.E5.A4.9A.E6.80.81.E5.AF.B9.E8.B1.A1">多态的</a>:其所标识的对象的<a href="cpp-language-types.html#.E5.8A.A8.E6.80.81.E7.B1.BB.E5.9E.8B">动态类型</a>不必是该表达式的静态类型。</li>
|
|
<li>泛左值可以具有<a href="cpp-language-types.html#.E4.B8.8D.E5.AE.8C.E6.95.B4.E7.B1.BB.E5.9E.8B">不完整类型</a>,只要表达式中容许。</li>
|
|
</ul>
|
|
<h4><span class="mw-headline" id=".E5.8F.B3.E5.80.BC">右值</span></h4>
|
|
<p><i>右值表达式</i>包括纯右值、亡值。</p>
|
|
<p>性质:</p>
|
|
<ul>
|
|
<li>右值不能由内建的取址运算符取地址:<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">&</span><span class="kw4">int</span><span class="br0">(</span><span class="br0">)</span></span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">&</span>i<span class="sy2">++</span></span></span><sup id="cite_ref-3" class="reference"><a href="cpp-language-value_category.html#cite_note-3">[3]</a></sup>、<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">&</span><span class="nu0">42</span></span></span> 及 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">&</span>std<span class="sy4">::</span><span class="me2">move</span><span class="br0">(</span>x<span class="br0">)</span></span></span> 是非法的。</li>
|
|
<li>右值不能用作内建赋值运算符及内建复合赋值运算符的左操作数。</li>
|
|
<li>右值可以用于<a href="cpp-language-reference_initialization.html">初始化 const 左值引用</a>,这种情况下该右值所标识的对象的生存期被<a href="cpp-language-reference_initialization.html#.E4.B8.B4.E6.97.B6.E5.AF.B9.E8.B1.A1.E7.9A.84.E7.94.9F.E5.AD.98.E6.9C.9F">延长</a>到该引用的作用域结尾。</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li>右值可以用于<a href="cpp-language-reference_initialization.html">初始化右值引用</a>,这种情况下该右值所标识的对象的生存期被<a href="cpp-language-reference_initialization.html#.E4.B8.B4.E6.97.B6.E5.AF.B9.E8.B1.A1.E7.9A.84.E7.94.9F.E5.AD.98.E6.9C.9F">延长</a>到该引用的作用域结尾。</li>
|
|
<li>当被用作函数实参且该函数有两种<a href="cpp-language-overload_resolution.html">重载</a>可用,其中之一接受右值引用的形参而另一个接受 const 的左值引用的形参时,右值将被绑定到右值引用的重载之上(从而,当复制与移动构造函数均可用时,以右值实参将调用其<a href="cpp-language-move_constructor.html">移动构造函数</a>,复制和移动赋值运算符与此类似)。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E7.89.B9.E6.AE.8A.E7.B1.BB.E5.88.AB">特殊类别</span></h3>
|
|
<h4><span class="mw-headline" id=".E6.9C.AA.E5.86.B3.E6.88.90.E5.91.98.E5.87.BD.E6.95.B0.E8.B0.83.E7.94.A8">未决成员函数调用</span></h4>
|
|
<p>表达式 <span class="t-c"><span class="mw-geshi cpp source-cpp">a.<span class="me1">mf</span></span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp">p<span class="sy2">-</span><span class="sy1">></span>mf</span></span>,其中 <code>mf</code> 是<a href="cpp-language-member_functions.html">非静态成员函数</a>,以及表达式 <span class="t-c"><span class="mw-geshi cpp source-cpp">a.<span class="sy2">*</span>pmf</span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp">p<span class="sy2">-</span><span class="sy1">></span><span class="sy2">*</span>pmf</span></span>,其中 <code>pmf</code> 是<a href="cpp-language-pointer.html#.E6.88.90.E5.91.98.E5.87.BD.E6.95.B0.E6.8C.87.E9.92.88">成员函数指针</a>,被归类为纯右值表达式,但它们不能用来初始化引用,作为函数实参,或者用于除了作为函数调用运算符的左操作数(例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="br0">(</span>p<span class="sy2">-</span><span class="sy1">></span><span class="sy2">*</span>pmf<span class="br0">)</span><span class="br0">(</span>args<span class="br0">)</span></span></span>)以外的任何目的。</p>
|
|
<h4><span class="mw-headline" id="void_.E8.A1.A8.E8.BE.BE.E5.BC.8F">void 表达式</span></h4>
|
|
<p>返回 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">void</span></span></span> 的函数调用表达式,转换为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">void</span></span></span> 的转型表达式,以及 <a href="cpp-language-throw.html">throw 表达式</a>,被归类为纯右值表达式,但它们不能用来初始化引用或者作为函数实参。它们可以用在舍弃值的语境(例如自成一行,作为逗号运算符的左操作数等)和返回 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">void</span></span></span> 的函数中的 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">return</span></span></span> 语句中。另外,throw 表达式可用作<a href="cpp-language-operator_other.html">条件运算符 <code>?:</code></a> 的第二个和第三个操作数。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx17">
|
|
<td>
|
|
<p>void 表达式没有<i>结果对象</i>。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h4><span class="mw-headline" id=".E4.BD.8D.E5.9F.9F">位域</span></h4>
|
|
<p>代表某个<a href="cpp-language-bit_field.html">位域</a>的表达式(例如 <span class="t-c"><span class="mw-geshi cpp source-cpp">a.<span class="me1">m</span></span></span>,其中 <code>a</code> 是类型 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">struct</span> A <span class="br0">{</span> <span class="kw4">int</span> m<span class="sy4">:</span> <span class="nu0">3</span><span class="sy4">;</span> <span class="br0">}</span></span></span> 的左值)是泛左值表达式:它可用作赋值运算符的左操作数,但它不能被取地址,并且非 const 的左值引用不能绑定于它。const 左值引用或右值引用可以从位域泛左值初始化,但这会制造位域的一个临时副本:它不会直接绑定到位域。</p>
|
|
<h3><span class="mw-headline" id=".E5.8E.86.E5.8F.B2">历史</span></h3>
|
|
<h4><span class="mw-headline" id="CPL">CPL</span></h4>
|
|
<p>编程语言 <a href="https://en.wikipedia.org/wiki/CPL_(programming_language)" class="extiw" title="enwiki:CPL (programming language)">CPL</a> 率先为表达式引入了值类别:所有 CPL 表达式都能以“右侧模式 (right-hand mode)”求值,但只有某些类型的表达式在“左侧模式 (left-hand mode)”有意义。在右侧模式中求值时,表达式被当做一条进行值的计算(右侧值,或<i>右值</i>)的规则。在左侧模式中求值时,表达式的效果则为给出一个地址(左侧值,或<i>左值</i>)。“左”和“右”代表“赋值之左”和“赋值之右”。</p>
|
|
<h4><span class="mw-headline" id="C">C</span></h4>
|
|
<p>C 编程语言遵循相似的分类法,但赋值的作用不再重要:C 的表达式被分为“左值 (lvalue) 表达式”和其他(函数和非对象值),其中“左值 (lvalue)”的含义为标识一个对象的表达式,即“定位器值 (locator value)”<sup id="cite_ref-4" class="reference"><a href="cpp-language-value_category.html#cite_note-4">[4]</a></sup>。</p>
|
|
<h4><span class="mw-headline" id="C.2B.2B98">C++98</span></h4>
|
|
<p>2011 年前的 C++ 遵循 C 模型,但恢复了对非左值表达式的“右值 (rvalue)”称呼,令函数为左值,并添加了引用能绑定到左值但唯有 const 的引用能绑定到右值的规则。几种非左值的 C 表达式在 C++ 中成为了左值表达式。</p>
|
|
<h4><span class="mw-headline" id="C.2B.2B11">C++11</span></h4>
|
|
<p>随着移动语义引入到 C++11 之中,值类别被重新进行了定义,以区别表达式的两种独立的性质<sup id="cite_ref-5" class="reference"><a href="cpp-language-value_category.html#cite_note-5">[5]</a></sup>:</p>
|
|
<ul>
|
|
<li><i>拥有身份 (identity)</i>:可以确定表达式是否与另一表达式指代同一实体,例如通过比较它们所标识的对象或函数的(直接或间接获得的)地址;</li>
|
|
<li><i>可被移动</i>:<a href="cpp-language-move_constructor.html">移动构造函数</a>、<a href="cpp-language-move_assignment.html">移动赋值运算符</a>或实现了移动语义的其他函数重载能够绑定于这个表达式。</li>
|
|
</ul>
|
|
<p>C++11 中:</p>
|
|
<ul>
|
|
<li>拥有身份且不可被移动的表达式被称作<i>左值 (lvalue)</i>表达式;</li>
|
|
<li>拥有身份且可被移动的表达式被称作<i>亡值 (xvalue)</i>表达式;</li>
|
|
<li>不拥有身份且可被移动的表达式被称作<i>纯右值 (prvalue)</i>表达式;</li>
|
|
<li>不拥有身份且不可被移动的表达式无法使用<sup id="cite_ref-6" class="reference"><a href="cpp-language-value_category.html#cite_note-6">[6]</a></sup>。</li>
|
|
</ul>
|
|
<p>拥有身份的表达式被称作“泛左值 (glvalue) 表达式”。左值和亡值都是泛左值表达式。</p>
|
|
<p>可被移动的表达式被称作“右值 (rvalue) 表达式”。纯右值和亡值都是右值表达式。</p>
|
|
<h4><span class="mw-headline" id="C.2B.2B17">C++17</span></h4>
|
|
<p>C++17 中,某些场合强制要求进行<a href="cpp-language-copy_elision.html">复制消除</a>,而这要求将纯右值表达式从被它们所初始化的临时对象中分离出来,这就是我们现有的系统。要注意,与 C++11 的方案相比,纯右值已不再是可被移动。</p>
|
|
<h3><span class="mw-headline" id=".E8.84.9A.E6.B3.A8">脚注</span></h3>
|
|
<ol class="references">
|
|
<li id="cite_note-1"><span class="mw-cite-backlink"><a href="cpp-language-value_category.html#cite_ref-1">↑</a></span> <span class="reference-text">假设 <span class="t-c"><span class="mw-geshi cpp source-cpp">i</span></span> 具有内建类型,或者其前置自增运算符被<a href="cpp-language-operators.html">重载</a>为返回左值引用。</span></li>
|
|
<li id="cite_note-pmfc-2"><span class="mw-cite-backlink">↑ <sup><a href="cpp-language-value_category.html#cite_ref-pmfc_2-0">2.0</a></sup> <sup><a href="cpp-language-value_category.html#cite_ref-pmfc_2-1">2.1</a></sup> <sup><a href="cpp-language-value_category.html#cite_ref-pmfc_2-2">2.2</a></sup> <sup><a href="cpp-language-value_category.html#cite_ref-pmfc_2-3">2.3</a></sup></span> <span class="reference-text">一种特殊的右值类别,参见未决成员函数调用。</span></li>
|
|
<li id="cite_note-3"><span class="mw-cite-backlink"><a href="cpp-language-value_category.html#cite_ref-3">↑</a></span> <span class="reference-text">假定 <span class="t-c"><span class="mw-geshi cpp source-cpp">i</span></span> 具有内建类型,或其后置自增运算符并未<a href="cpp-language-operators.html">重载</a>为返回左值引用。</span></li>
|
|
<li id="cite_note-4"><span class="mw-cite-backlink"><a href="cpp-language-value_category.html#cite_ref-4">↑</a></span> <span class="reference-text">“C 社区中对此的观点主要围绕着 lvalue 的含义而有所差异,一组人认为 lvalue 是任何种类的对象定位器,另一组人认为 lvalue 在赋值运算符的左侧时才有意义。C89 委员会采纳了作为对象定位器的定义。”—— ANSI C 基本原理,6.3.2.1/10 。</span></li>
|
|
<li id="cite_note-5"><span class="mw-cite-backlink"><a href="cpp-language-value_category.html#cite_ref-5">↑</a></span> <span class="reference-text"><a rel="nofollow" class="external text" href="http://www.stroustrup.com/terminology.pdf">新·值术语</a>,Bjarne Stroustrup,2010。</span></li>
|
|
<li id="cite_note-6"><span class="mw-cite-backlink"><a href="cpp-language-value_category.html#cite_ref-6">↑</a></span> <span class="reference-text">const 纯右值(仅允许类类型)及 const 亡值不能绑定于 T&& 的重载,但它们可以绑定于 const T&& 的重载——由于其满足这种分类中的“可被移动”的定义,标准中将这种重载也归类为“移动构造函数”和“移动赋值运算符”。然而,这种重载无法修改它们的参数,并且在实践中并不使用;当没有这种重载时,const 纯右值和 const 亡值绑定于 const T& 的重载。</span></li>
|
|
</ol>
|
|
<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/issue616">CWG 616</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/issue1213">CWG 1213</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>
|