1090 lines
123 KiB
HTML
1090 lines
123 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>Lambda 表达式 (C++11 起)</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_lambda skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading">Lambda 表达式 <span class="t-mark-rev t-since-cxx11">(C++11 起)</span></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="https://en.wikipedia.org/wiki/Closure_(computer_science)" class="extiw" title="enwiki:Closure (computer science)">闭包</a>:能够捕获作用域中的变量的无名函数对象。</p>
|
|
<h3><span class="mw-headline" id=".E8.AF.AD.E6.B3.95">语法</span></h3>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>[</b></code> <span class="t-spar">捕获</span> <code><b>]</b></code> <code><b>(</b></code> <span class="t-spar">形参</span> <code><b>)</b></code> <span class="t-spar">lambda说明符</span> <span class="t-spar">约束</span><span class="t-mark">(可选)</span> <code><b>{</b></code> <span class="t-spar">函数体</span> <code><b>}</b></code></td>
|
|
<td>(1)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>[</b></code> <span class="t-spar">捕获</span> <code><b>]</b></code> <code><b>{</b></code> <span class="t-spar">函数体</span> <code><b>}</b></code></td>
|
|
<td>(2)</td>
|
|
<td><span class="t-mark-rev t-until-cxx23">(C++23 前)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>[</b></code> <span class="t-spar">捕获</span> <code><b>]</b></code> <span class="t-spar">lambda说明符</span> <code><b>{</b></code> <span class="t-spar">函数体</span> <code><b>}</b></code></td>
|
|
<td>(2)</td>
|
|
<td><span class="t-mark-rev t-since-cxx23">(C++23 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>[</b></code> <span class="t-spar">捕获</span> <code><b>]</b></code> <span class="t-spar"><模板形参></span> <span class="t-spar">约束</span><span class="t-mark">(可选)</span><br />
|
|
<code><b>(</b></code> <span class="t-spar">形参</span> <code><b>)</b></code> <span class="t-spar">lambda说明符</span> <span class="t-spar">约束</span><span class="t-mark">(可选)</span> <code><b>{</b></code> <span class="t-spar">函数体</span> <code><b>}</b></code></td>
|
|
<td>(3)</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>[</b></code> <span class="t-spar">捕获</span> <code><b>]</b></code> <span class="t-spar"><模板形参></span> <span class="t-spar">约束</span><span class="t-mark">(可选)</span> <code><b>{</b></code> <span class="t-spar">函数体</span> <code><b>}</b></code></td>
|
|
<td>(4)</td>
|
|
<td><span class="t-su t-su-b"><span class="t-mark-rev t-since-cxx20">(C++20 起)</span><br />
|
|
<span class="t-mark-rev t-until-cxx23">(C++23 前)</span></span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>[</b></code> <span class="t-spar">捕获</span> <code><b>]</b></code> <span class="t-spar"><模板形参></span> <span class="t-spar">约束</span><span class="t-mark">(可选)</span> <span class="t-spar">lambda说明符</span> <code><b>{</b></code> <span class="t-spar">函数体</span> <code><b>}</b></code></td>
|
|
<td>(4)</td>
|
|
<td><span class="t-mark-rev t-since-cxx23">(C++23 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">1)</span> 完整声明。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 省略形参列表:函数不接收实参,如同形参列表是 <code><b>()</b></code>。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 与 1) 相同,但指定泛型 lambda 并显式提供模板形参列表。</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 与 2) 相同,但指定泛型 lambda 并显式提供模板形参列表。</div>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<table class="t-par-begin">
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">捕获</span></td>
|
|
<td>-</td>
|
|
<td>包含零或更多个<a href="cpp-language-lambda.html#Lambda_.E6.8D.95.E8.8E.B7">捕获符</a>的逗号分隔列表,可以 <span class="t-spar">默认捕获符(capture-default)</span> 起始。
|
|
<p>有关捕获符的详细描述,见<a href="cpp-language-lambda.html#Lambda_.E6.8D.95.E8.8E.B7">下文</a>。 如果变量满足下列条件,那么 lambda 表达式在使用它前不需要先捕获:</p>
|
|
<ul>
|
|
<li>该变量是非局部变量,或具有静态或线程局部<a href="cpp-language-storage_duration.html">存储期</a>(此时无法捕获该变量),或者</li>
|
|
<li>该变量是以<a href="cpp-language-constant_expression.html#.E5.B8.B8.E9.87.8F.E8.A1.A8.E8.BE.BE.E5.BC.8F">常量表达式</a>初始化的引用。</li>
|
|
</ul>
|
|
<p>如果变量满足下列条件,那么 lambda 表达式在读取它的值前不需要先捕获:</p>
|
|
<ul>
|
|
<li>该变量具有 const 而非 volatile 的整型或枚举类型,并已经用<a href="cpp-language-constant_expression.html#.E5.B8.B8.E9.87.8F.E8.A1.A8.E8.BE.BE.E5.BC.8F">常量表达式</a>初始化,或者</li>
|
|
<li>该变量是 <code>constexpr</code> 的且没有 mutable 成员。</li>
|
|
</ul>
|
|
</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar"><模板形参></span></td>
|
|
<td>-</td>
|
|
<td>(角括号中的)模板形参列表,用于为泛型 lambda 提供各模板形参的名字(见下文的 <code>闭包类型::operator()</code>)。与在<a href="cpp-language-templates.html">模板声明</a>中相似,模板形参列表可以后附 requires 子句,它指定各模板实参上的<a href="cpp-language-constraints.html">约束</a>。
|
|
<p>模板形参列表不能为空(不允许 <code><></code>)。</p>
|
|
</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">形参</span></td>
|
|
<td>-</td>
|
|
<td>形参列表,如在<a href="cpp-language-function.html">具名函数中</a>。</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">lambda说明符</span></td>
|
|
<td>-</td>
|
|
<td>由 <span class="t-spar">说明符</span>、 <span class="t-spar">异常说明</span>、 <span class="t-spar">属性</span> 和 <span class="t-spar">尾随返回类型</span> 按顺序组成,每个组分均非必需</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">说明符</span></td>
|
|
<td>-</td>
|
|
<td>可选的说明符的序列。不提供说明符时复制捕获的对象在 lambda 体内是 const 的。可以使用下列说明符:
|
|
<ul>
|
|
<li><code><b>mutable</b></code>:允许 <span class="t-spar">函数体</span> 修改复制捕获的对象,以及调用它们的非 const 成员函数</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx17">
|
|
<td>
|
|
<ul>
|
|
<li><code><b>constexpr</b></code>:显式指定函数调用运算符或运算符模板的任意特化为 <a href="cpp-language-constexpr.html">constexpr</a> 函数。如果没有此说明符但函数调用运算符或任意给定的运算符模板特化恰好满足针对 constexpr 函数的所有要求,那么它也会是 <code>constexpr</code> 的</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<ul>
|
|
<li><code><b>consteval</b></code>:指定函数调用运算符或任意给定的运算符模板特化为<a href="cpp-language-consteval.html">立即函数</a>。不能同时使用 <code>consteval</code> 和 <code>constexpr</code>。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">异常说明</span></td>
|
|
<td>-</td>
|
|
<td>为闭包类型的 <code>operator()</code> 提供<span class="t-rev-inl t-until-cxx20"><span><a href="cpp-language-except_spec.html">动态异常说明</a>或</span> <span><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></span></span> <a href="cpp-language-noexcept_spec.html">noexcept 说明符</a></td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">属性</span></td>
|
|
<td>-</td>
|
|
<td>为闭包类型的函数调用运算符或运算符模板的类型提供<a href="cpp-language-attributes.html">属性说明</a>。这样指定的任何属性均属于函数调用运算符或运算符模板的类型,而非其自身。(例如不能使用 <code>[[<a href="cpp-language-attributes-noreturn.html">noreturn</a>]]</code> )</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">尾随返回类型</span></td>
|
|
<td>-</td>
|
|
<td><code><b>-></b></code> <span class="t-spar">返回类型</span> ,其中 <span class="t-spar">返回类型</span> 指定返回类型。如果没有 <span class="t-spar">尾随返回类型</span>,那么闭包的 <code>operator()</code> 的返回类型从 <a href="cpp-language-return.html">return</a> 语句<a href="cpp-language-template_argument_deduction.html">推导</a>,如同对于<a href="cpp-language-function.html#.E8.BF.94.E5.9B.9E.E7.B1.BB.E5.9E.8B.E6.8E.A8.E5.AF.BC">声明返回类型为 auto</a> 的函数的推导一样。</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">约束</span></td>
|
|
<td>-</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span>向闭包类型的 <code>operator()</code> 添加<a href="cpp-language-constraints.html">约束</a></td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">函数体</span></td>
|
|
<td>-</td>
|
|
<td>函数体</td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx14">
|
|
<td>
|
|
<p>当以 <a href="cpp-language-auto.html"><code>auto</code></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>时,该 lambda 为<i>泛型 lambda</i>。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>lambda 表达式是纯右值表达式,它的类型是独有的无名非联合非聚合类类型,被称为<i>闭包类型(closure type)</i>,它(对于 <a href="cpp-language-adl.html">ADL</a> 而言)在含有该 lambda 表达式的最小块作用域、类作用域或命名空间作用域声明。闭包类型有下列成员:</p>
|
|
<div class="t-member">
|
|
<h2><span class="mw-headline" id=".E9.97.AD.E5.8C.85.E7.B1.BB.E5.9E.8B::operator.28.29.28.E5.BD.A2.E5.8F.82.29"><span style="font-size:0.7em; line-height:130%">闭包类型::</span>operator()(<span class="t-spar">形参</span>)</span></h2>
|
|
<table class="t-dcl-begin">
|
|
<tbody>
|
|
<tr class="t-dcl">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp">返回类型 operator<span class="br0">(</span><span class="br0">)</span><span class="br0">(</span>形参<span class="br0">)</span> <span class="kw4">const</span> <span class="br0">{</span> 函数体 <span class="br0">}</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark">(未使用关键词 mutable)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp">返回类型 operator<span class="br0">(</span><span class="br0">)</span><span class="br0">(</span>形参<span class="br0">)</span> <span class="br0">{</span> 函数体 <span class="br0">}</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark">(使用了关键词 mutable)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl t-since-cxx14">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp"><span class="kw1">template</span><span class="sy1"><</span>模板形参<span class="sy1">></span><br />
|
|
返回类型 operator<span class="br0">(</span><span class="br0">)</span><span class="br0">(</span>形参<span class="br0">)</span> <span class="kw4">const</span> <span class="br0">{</span> 函数体 <span class="br0">}</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span><br />
|
|
<span class="t-mark">(泛型 lambda)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl t-since-cxx14">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp"><span class="kw1">template</span><span class="sy1"><</span>模板形参<span class="sy1">></span><br />
|
|
返回类型 operator<span class="br0">(</span><span class="br0">)</span><span class="br0">(</span>形参<span class="br0">)</span> <span class="br0">{</span> 函数体 <span class="br0">}</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span><br />
|
|
<span class="t-mark">(泛型 lambda,使用了关键词 mutable)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl-sep">
|
|
<td></td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>当被调用时,执行 lambda 表达式的函数体。当访问变量时,访问的是其被捕获的副本(对于以复制捕获的实体)或原对象(对于以引用捕获的实体)。除非 lambda 表达式中使用了关键词 <span class="t-c"><span class="mw-geshi cpp source-cpp">mutable</span></span>,否则函数调用运算符或运算符模板会被 const 限定,且无法从这个 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="br0">(</span><span class="br0">)</span></span></span> 的内部修改以复制捕获的对象。函数调用运算符或运算符模板始终不被 volatile 限定且始终非虚。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx17">
|
|
<td>
|
|
<p>如果函数调用运算符或任意给定的运算符模板特化满足针对 <a href="cpp-language-constexpr.html">constexpr 函数</a>的要求,那么它始终是 constexpr 的。如果关键词 <code>constexpr</code> 用于 lambda 声明,那么它也是 constexpr 的。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>如果在 lambda 表达式中使用关键词 <code>consteval</code>,那么函数调用运算符或任意给定的运算符模板特化是<a href="cpp-language-consteval.html">立即函数</a>。</p>
|
|
</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-cxx14">
|
|
<td>
|
|
<p>对于 <span class="t-spar">形参</span> 中每个类型指定为 <code>auto</code> 的参数,以其出现顺序向 <span class="t-spar">模板形参</span> 中添加一个虚设的模板形参。当虚设的模板形参所对应的 <span class="t-spar">形参</span> 中的函数形参是函数形参包时,它可以是<a href="cpp-language-parameter_pack.html">形参包</a>。</p>
|
|
<div style="text-align: left; width:45em" dir="ltr" class="mw-geshi">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co1">// 泛型 lambda,operator() 是有两个形参的模板</span>
|
|
<span class="kw4">auto</span> glambda <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> a, <span class="kw4">auto</span><span class="sy3">&&</span> b<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> a <span class="sy1"><</span> b<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">bool</span> b <span class="sy1">=</span> glambda<span class="br0">(</span><span class="nu0">3</span>, <span class="nu16">3.14</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// ok</span>
|
|
|
|
<span class="co1">// 泛型 lambda,operator() 是有一个形参的模板</span>
|
|
<span class="kw4">auto</span> vglambda <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> printer<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> <span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span><span class="sy3">&&</span>... <span class="me1">ts</span><span class="br0">)</span> <span class="co1">// 泛型 lambda,ts 是形参包</span>
|
|
<span class="br0">{</span>
|
|
printer<span class="br0">(</span><a href="cpp-utility-forward.html"><span class="kw1117">std::<span class="me2">forward</span></span></a><span class="sy1"><</span>decltype<span class="br0">(</span>ts<span class="br0">)</span><span class="sy1">></span><span class="br0">(</span>ts<span class="br0">)</span>...<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw1">return</span> <span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span> <span class="br0">{</span> printer<span class="br0">(</span>ts...<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 零元 lambda (不接受形参)</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> p <span class="sy1">=</span> vglambda<span class="br0">(</span><span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> v1, <span class="kw4">auto</span> v2, <span class="kw4">auto</span> v3<span class="br0">)</span> <span class="br0">{</span> <a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> v1 <span class="sy1"><<</span> v2 <span class="sy1"><<</span> v3<span class="sy4">;</span> <span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> q <span class="sy1">=</span> p<span class="br0">(</span><span class="nu0">1</span>, <span class="st0">'a'</span>, <span class="nu16">3.14</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 输出 1a3.14</span>
|
|
q<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 输出 1a3.14</span></pre></div>
|
|
</div>
|
|
<p><code>闭包类型</code> 的 <code>operator()</code> 不能被显式实例化或显式特化。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>如果 lambda 定义使用显式的模板形参列表,那么该模板形参列表会用于 <code>operator()</code>。对于 <span class="t-spar">形参</span> 中每个类型指定为 <code>auto</code> 的形参,都会有一个额外的虚设模板形参追加到模板形参列表尾部:</p>
|
|
<div style="text-align: left; width:45em" dir="ltr" class="mw-geshi">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co1">// 泛型 lambda,operator() 是有两个形参的模板</span>
|
|
<span class="kw4">auto</span> glambda <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span><span class="br0">(</span>T a, <span class="kw4">auto</span><span class="sy3">&&</span> b<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> a <span class="sy1"><</span> b<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 泛型 lambda,operator() 是有一个形参包的模板</span>
|
|
<span class="kw4">auto</span> f <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="sy1"><</span><span class="kw1">typename</span> ...<span class="me1">Ts</span><span class="sy1">></span><span class="br0">(</span>Ts<span class="sy3">&&</span> ...<span class="me1">ts</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> foo<span class="br0">(</span><a href="cpp-utility-forward.html"><span class="kw1117">std::<span class="me2">forward</span></span></a><span class="sy1"><</span>Ts<span class="sy1">></span><span class="br0">(</span>ts<span class="br0">)</span>...<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>lambda 表达式上的异常说明 <span class="t-spar">异常说明</span> 应用于函数调用运算符或运算符模板。</p>
|
|
<p>对于<a href="cpp-language-lookup.html">名字查找</a>、确定 <a href="cpp-language-this.html">this 指针</a>的类型和值以及对于访问非静态类成员而言,闭包类型的函数调用运算符的函数体被认为处于 lambda 表达式的语境中。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> X <span class="br0">{</span>
|
|
<span class="kw4">int</span> x, y<span class="sy4">;</span>
|
|
<span class="kw4">int</span> operator<span class="br0">(</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="co1">// 下列 lambda 的语境是成员函数 X::f</span>
|
|
<span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span><span class="br0">(</span><span class="br0">)</span><span class="sy2">-</span><span class="sy1">></span><span class="kw4">int</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">return</span> operator<span class="br0">(</span><span class="br0">)</span><span class="br0">(</span>this<span class="sy2">-</span><span class="sy1">></span>x <span class="sy2">+</span> y<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// X::operator()(this->x + (*this).y)</span>
|
|
<span class="co1">// this 拥有类型 X*</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p><code>闭包类型</code> 的 <code>operator()</code> 不能在<a href="cpp-language-friend.html">友元</a>声明中指名。</p>
|
|
<h3><span class="mw-headline" id=".E6.82.AC.E5.9E.82.E5.BC.95.E7.94.A8">悬垂引用</span></h3>
|
|
<p>如果以引用隐式或显式捕获非引用实体,而在该实体的生存期结束之后调用闭包对象的函数调用运算符或运算符模板特化,那么会发生未定义行为。C++ 的闭包并不延长以引用捕获的对象的生存期。</p>
|
|
<p>这同样适用于由 <code>this</code> 捕获对当前 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">*</span>this</span></span> 对象。</p>
|
|
</div>
|
|
<div class="t-member">
|
|
<h2><span class="mw-headline" id=".E9.97.AD.E5.8C.85.E7.B1.BB.E5.9E.8B::operator_.E8.BF.94.E5.9B.9E.E7.B1.BB.E5.9E.8B.28.2A.29.28.E5.BD.A2.E5.8F.82.29.28.29"><span style="font-size:0.7em; line-height:130%">闭包类型::</span>operator <span class="t-spar">返回类型</span>(*)(<span class="t-spar">形参</span>)()</span></h2>
|
|
<table class="t-dcl-begin">
|
|
<tbody>
|
|
<tr class="t-dcl-sep">
|
|
<td></td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
<tr class="t-dcl-h">
|
|
<td>
|
|
<div>无捕获的非泛型 lambda</div>
|
|
</td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
<tbody class="t-dcl-rev">
|
|
<tr class="t-dcl t-until-cxx17">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp"><span class="kw1">using</span> F <span class="sy1">=</span> 返回类型<span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span>形参<span class="br0">)</span><span class="sy4">;</span><br />
|
|
operator F<span class="br0">(</span><span class="br0">)</span> <span class="kw4">const</span> <span class="kw1">noexcept</span><span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl t-since-cxx17">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp"><span class="kw1">using</span> F <span class="sy1">=</span> 返回类型<span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span>形参<span class="br0">)</span><span class="sy4">;</span><br />
|
|
<span class="kw4">constexpr</span> operator F<span class="br0">(</span><span class="br0">)</span> <span class="kw4">const</span> <span class="kw1">noexcept</span><span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</tbody>
|
|
<tbody>
|
|
<tr class="t-dcl-sep">
|
|
<td></td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
<tr class="t-dcl-h">
|
|
<td>
|
|
<div>无捕获的泛型 lambda</div>
|
|
</td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
<tbody class="t-dcl-rev">
|
|
<tr class="t-dcl t-since-cxx14 t-until-cxx17">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp"><span class="kw1">template</span><span class="sy1"><</span>模板形参<span class="sy1">></span> <span class="kw1">using</span> fptr_t <span class="sy1">=</span> <span class="coMULTI">/*见下文*/</span><span class="sy4">;</span><br /></span>
|
|
<p><span class="kw1">template</span><span class="sy1"><</span>模板形参<span class="sy1">></span><br /></p>
|
|
operator fptr_t<span class="sy1"><</span>模板形参<span class="sy1">></span><span class="br0">(</span><span class="br0">)</span> <span class="kw4">const</span> <span class="kw1">noexcept</span><span class="sy4">;</span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span><br />
|
|
<span class="t-mark-rev t-until-cxx17">(C++17 前)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl t-since-cxx17">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp"><span class="kw1">template</span><span class="sy1"><</span>模板形参<span class="sy1">></span> <span class="kw1">using</span> fptr_t <span class="sy1">=</span> <span class="coMULTI">/*见下文*/</span><span class="sy4">;</span><br /></span>
|
|
<p><span class="kw1">template</span><span class="sy1"><</span>模板形参<span class="sy1">></span><br /></p>
|
|
<span class="kw4">constexpr</span> operator fptr_t<span class="sy1"><</span>模板形参<span class="sy1">></span><span class="br0">(</span><span class="br0">)</span> <span class="kw4">const</span> <span class="kw1">noexcept</span><span class="sy4">;</span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</tbody>
|
|
<tbody>
|
|
<tr class="t-dcl-sep">
|
|
<td></td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>只有在 lambda 表达式的捕获符列表为空时才定义这个<a href="cpp-language-cast_operator.html">用户定义转换函数</a>。它是闭包对象的公开、<span class="t-rev-inl t-since-cxx17"><span>constexpr、</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>非虚、非 explicit、const noexcept 成员函数。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>如果函数调用运算符(或对于泛型 lambda 为其特化)是立即函数,那么此函数是<a href="cpp-language-consteval.html">立即函数</a>。</p>
|
|
</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-cxx14">
|
|
<td>
|
|
<p>泛型无捕获 lambda 拥有一个用户定义的转换函数模板,它具有与函数调用运算符模板相同的虚设模板形参列表。如果它的返回类型为空或 <code>auto</code>,那么将由函数模板特化上的返回类型推导获得,而它会以转换函数模板的<a href="cpp-language-template_argument_deduction.html">模板实参推导</a>获得。</p>
|
|
<div style="text-align: left; width:45em" dir="ltr" class="mw-geshi">
|
|
<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="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span>
|
|
<span class="kw4">void</span> f2<span class="br0">(</span><span class="kw4">char</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="br0">)</span> <span class="br0">{</span><span class="br0">}</span>
|
|
<span class="kw4">void</span> h<span class="br0">(</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="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="co1">// #1</span>
|
|
<span class="kw4">void</span> h<span class="br0">(</span><span class="kw4">char</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="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="co1">// #2</span>
|
|
<span class="kw4">auto</span> glambda <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> a<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> a<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
f1<span class="br0">(</span>glambda<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
f2<span class="br0">(</span>glambda<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误:不可转换</span>
|
|
h<span class="br0">(</span>glambda<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK:调用 #1,因为 #2 不可转换</span>
|
|
|
|
<span class="kw4">int</span><span class="sy3">&</span> <span class="br0">(</span><span class="sy2">*</span>fpi<span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span><span class="br0">)</span> <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span><span class="sy2">*</span> a<span class="br0">)</span><span class="sy2">-</span><span class="sy1">></span><span class="kw4">auto</span><span class="sy3">&</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="sy2">*</span>a<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>这个转换函数所返回一个指向具有 C++ <a href="cpp-language-language_linkage.html">语言连接</a>的函数指针,调用该函数的效果与直接调用闭包对象的函数调用运算符相同。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx17">
|
|
<td>
|
|
<p>如果函数调用运算符(或对于泛型 lambda 为其特化)是 constexpr 的,那么此函数也是 constexpr 的。</p>
|
|
<div style="text-align: left; width:45em" dir="ltr" class="mw-geshi">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">auto</span> Fwd<span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">(</span><span class="sy2">*</span>fp<span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span>, <span class="kw4">auto</span> a<span class="br0">)</span><span class="br0">{</span><span class="kw1">return</span> fp<span class="br0">(</span>a<span class="br0">)</span><span class="sy4">;</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> C<span class="sy1">=</span><span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> a<span class="br0">)</span><span class="br0">{</span><span class="kw1">return</span> a<span class="sy4">;</span><span class="br0">}</span><span class="sy4">;</span>
|
|
static_assert<span class="br0">(</span>Fwd<span class="br0">(</span>C,<span class="nu0">3</span><span class="br0">)</span><span class="sy1">==</span><span class="nu0">3</span><span class="br0">)</span><span class="sy4">;</span><span class="co1">// OK</span>
|
|
<span class="kw4">auto</span> NC<span class="sy1">=</span><span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> a<span class="br0">)</span><span class="br0">{</span> <span class="kw4">static</span> <span class="kw4">int</span> s<span class="sy4">;</span> <span class="kw1">return</span> a<span class="sy4">;</span><span class="br0">}</span><span class="sy4">;</span>
|
|
static_assert<span class="br0">(</span>Fwd<span class="br0">(</span>NC,<span class="nu0">3</span><span class="br0">)</span><span class="sy1">==</span><span class="nu0">3</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误:因为 static s 而不能为 constexpr 的特化</span></pre></div>
|
|
</div>
|
|
<p><span class="t-rev-inl t-until-cxx20"><span>如果闭包对象的 <code>operator()</code> 具有无抛出异常说明,那么此函数返回的指针具有指向 noexcept 函数的指针类型。</span> <span><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></span></span></p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="t-member">
|
|
<h2><span class="mw-headline" id=".E9.97.AD.E5.8C.85.E7.B1.BB.E5.9E.8B::.E9.97.AD.E5.8C.85.E7.B1.BB.E5.9E.8B.28.29"><span style="font-size:0.7em; line-height:130%">闭包类型::</span>闭包类型()</span></h2>
|
|
<table class="t-dcl-begin">
|
|
<tbody>
|
|
<tr class="t-dcl">
|
|
<td class="t-dcl-nopad">
|
|
<div><span class="mw-geshi cpp source-cpp">闭包类型<span class="br0">(</span><span class="br0">)</span> <span class="sy1">=</span> delete<span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td class="t-dcl-nopad"></td>
|
|
</tr>
|
|
<tr class="t-dcl t-since-cxx20">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp">闭包类型<span class="br0">(</span><span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span><br />
|
|
<span class="t-mark">(仅当未指定任何捕获时)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl">
|
|
<td class="t-dcl-nopad">
|
|
<div><span class="mw-geshi cpp source-cpp">闭包类型<span class="br0">(</span><span class="kw4">const</span> 闭包类型<span class="sy3">&</span> <span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td class="t-dcl-nopad"></td>
|
|
</tr>
|
|
<tr class="t-dcl">
|
|
<td class="t-dcl-nopad">
|
|
<div><span class="mw-geshi cpp source-cpp">闭包类型<span class="br0">(</span>闭包类型<span class="sy3">&&</span> <span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td class="t-dcl-nopad"></td>
|
|
</tr>
|
|
<tr class="t-dcl-sep">
|
|
<td></td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<p>闭包类型非<a href="cpp-named_req-DefaultConstructible.html"><span style="font-style:italic">可默认构造</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(DefaultConstructible)</span></a> 。闭包类型没有默认构造函数。</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>如果没有指定 <span class="t-spar">捕获</span>,那么闭包类型拥有预置的默认构造函数。否则,它没有默认构造函数(这包含有 <span class="t-spar">默认捕获符(capture-default)</span> 的情况,即使它实际上没有捕获任何变量)。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>复制构造函数与移动构造函数声明为预置,并可能按照<a href="cpp-language-copy_constructor.html">复制构造函数</a>与<a href="cpp-language-move_constructor.html">移动构造函数</a>的通常规则隐式定义。</p>
|
|
</div>
|
|
<div class="t-member">
|
|
<h2><span class="mw-headline" id=".E9.97.AD.E5.8C.85.E7.B1.BB.E5.9E.8B::operator.3D.28const_.E9.97.AD.E5.8C.85.E7.B1.BB.E5.9E.8B.26.29"><span style="font-size:0.7em; line-height:130%">闭包类型::</span>operator=(const 闭包类型&)</span></h2>
|
|
<table class="t-dcl-begin">
|
|
<tbody>
|
|
<tr class="t-dcl t-until-cxx20">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp">闭包类型<span class="sy3">&</span> operator<span class="sy1">=</span><span class="br0">(</span><span class="kw4">const</span> 闭包类型<span class="sy3">&</span><span class="br0">)</span> <span class="sy1">=</span> delete<span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl t-since-cxx20">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp">闭包类型<span class="sy3">&</span> operator<span class="sy1">=</span><span class="br0">(</span><span class="kw4">const</span> 闭包类型<span class="sy3">&</span><span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span><br />
|
|
闭包类型<span class="sy3">&</span> operator<span class="sy1">=</span><span class="br0">(</span>闭包类型<span class="sy3">&&</span><span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span><br />
|
|
<span class="t-mark">(仅当未指定任何捕获时)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl t-since-cxx20">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp">闭包类型<span class="sy3">&</span> operator<span class="sy1">=</span><span class="br0">(</span><span class="kw4">const</span> 闭包类型<span class="sy3">&</span><span class="br0">)</span> <span class="sy1">=</span> delete<span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span><br />
|
|
<span class="t-mark">(其他情况)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl-sep">
|
|
<td></td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<p>复制赋值运算符被定义为弃置的(且未声明移动赋值运算符)。闭包类型非<a href="cpp-named_req-CopyAssignable.html"><span style="font-style:italic">可复制赋值</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(CopyAssignable)</span></a> 。</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>如果没有指定 <span class="t-spar">捕获</span>,那么闭包类型拥有预置的复制赋值运算符和预置的移动赋值运算符。否则,它拥有弃置的复制赋值运算符(这包含有 <span class="t-spar">默认捕获符</span> 的情况,即使它实际上没有捕获任何变量)。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="t-member">
|
|
<h2><span class="mw-headline" id=".E9.97.AD.E5.8C.85.E7.B1.BB.E5.9E.8B::.7E.E9.97.AD.E5.8C.85.E7.B1.BB.E5.9E.8B.28.29"><span style="font-size:0.7em; line-height:130%">闭包类型::</span>~闭包类型()</span></h2>
|
|
<table class="t-dcl-begin">
|
|
<tbody>
|
|
<tr class="t-dcl">
|
|
<td class="t-dcl-nopad">
|
|
<div><span class="mw-geshi cpp source-cpp">~闭包类型<span class="br0">(</span><span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td class="t-dcl-nopad"></td>
|
|
</tr>
|
|
<tr class="t-dcl-sep">
|
|
<td></td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>析构函数是隐式声明的。</p>
|
|
</div>
|
|
<div class="t-member">
|
|
<h2><span class="mw-headline" id=".E9.97.AD.E5.8C.85.E7.B1.BB.E5.9E.8B::.E6.8D.95.E8.8E.B7"><span style="font-size:0.7em; line-height:130%">闭包类型::</span><span class="t-spar">捕获</span></span></h2>
|
|
<table class="t-dcl-begin">
|
|
<tbody>
|
|
<tr class="t-dcl">
|
|
<td class="t-dcl-nopad">
|
|
<div><span class="mw-geshi cpp source-cpp">T1 a<span class="sy4">;</span><br /></span>
|
|
<p>T2 b<span class="sy4">;</span><br /></p>
|
|
...</div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td class="t-dcl-nopad"></td>
|
|
</tr>
|
|
<tr class="t-dcl-sep">
|
|
<td></td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>如果 lambda 表达式以复制(隐式地以捕获子句 <code><b>[=]</b></code> 或显式地以不含字符 & 的捕获符,例如 <code><b>[a, b, c]</b></code>)捕获了任何内容,那么闭包类型包含保有所有被如此捕获的实体的副本的无名非静态数据成员,它们以未指明的顺序声明。</p>
|
|
<p>如果数据成员对应的捕获符没有初始化器,那么它们在求值 lambda 表达式时被<a href="cpp-language-direct_initialization.html">直接初始化</a>。如果有初始化器,那么按其初始化器的要求初始化(可为复制或直接初始化)。如果捕获了数组,那么各数组元素以下标递增顺序直接初始化。初始化各数据成员所用的顺序是它们的声明顺序(即未指明)。</p>
|
|
<p>每个数据成员的类型是其对应被捕获实体的类型,除非实体拥有引用类型(此时到函数的引用被捕获为到被引用函数的左值引用,而到对象的引用被捕获为被引用对象的副本)。</p>
|
|
<p>对于以引用捕获(以默认捕获符 <code><b>[&]</b></code> 或使用了字符 &,例如 <code><b>[&a, &b, &c]</b></code>)的实体,闭包类型中是否声明额外的数据成员是未指明的<span class="t-rev-inl t-since-cxx17"><span>,但任何这种附加成员必须满足<a href="cpp-named_req-LiteralType.html"><span style="font-style:italic">字面类型</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(LiteralType)</span></a></span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>。</p>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<p><span id=".E4.B8.8D.E6.B1.82.E5.80.BC.E8.AF.AD.E5.A2.83.E4.B8.AD.E7.9A.84_lambda"></span> 不允许在<a href="cpp-language-expressions.html#.E4.B8.8D.E6.B1.82.E5.80.BC.E8.A1.A8.E8.BE.BE.E5.BC.8F">不求值表达式</a>、<a href="cpp-language-template_parameters.html">模板实参</a>、<a href="cpp-language-type_alias.html">别名声明</a>、<a href="cpp-language-typedef.html">typedef 声明</a>,以及函数(或函数模板)声明中除了函数体和函数的<a href="cpp-language-default_arguments.html">默认实参</a>以外的任何位置中出现 lambda 表达式。</p>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:详细阐述 C++20 对此的变更</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id="Lambda_.E6.8D.95.E8.8E.B7">Lambda 捕获</span></h3>
|
|
<p><span class="t-spar">捕获</span> 是一个含有零或更多个<i>捕获符</i>的逗号分隔列表,可以 <span class="t-spar">默认捕获符</span> 开始。默认捕获符只有</p>
|
|
<ul>
|
|
<li><code><b>&</b></code>(以引用隐式捕获被使用的自动变量)和</li>
|
|
<li><code><b>=</b></code> (以复制隐式捕获被使用的自动变量)。</li>
|
|
</ul>
|
|
<p>当出现任一默认捕获符时,都能隐式捕获当前对象(<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">*</span>this</span></span>)。当它被隐式捕获时,始终被以引用捕获,即使默认捕获符是 <code>=</code>。<span class="t-rev-inl t-since-cxx20"><span>当默认捕获符为 <code>=</code> 时,<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">*</span>this</span></span> 的隐式捕获被弃用。</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span></p>
|
|
<p><span class="t-spar">捕获</span> 中单独的捕获符的语法是</p>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">标识符</span></td>
|
|
<td>(1)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">标识符</span> <code><b>...</b></code></td>
|
|
<td>(2)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">标识符</span> <span class="t-spar">初始化器</span></td>
|
|
<td>(3)</td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>&</b></code> <span class="t-spar">标识符</span></td>
|
|
<td>(4)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>&</b></code> <span class="t-spar">标识符</span> <code><b>...</b></code></td>
|
|
<td>(5)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>&</b></code> <span class="t-spar">标识符</span> <span class="t-spar">初始化器</span></td>
|
|
<td>(6)</td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>this</b></code></td>
|
|
<td>(7)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>*</b></code> <code><b>this</b></code></td>
|
|
<td>(8)</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>...</b></code> <span class="t-spar">标识符</span> <span class="t-spar">初始化器</span></td>
|
|
<td>(9)</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>&</b></code> <code><b>...</b></code> <span class="t-spar">标识符</span> <span class="t-spar">初始化器</span></td>
|
|
<td>(10)</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">1)</span> 简单以复制捕获</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 作为<a href="cpp-language-parameter_pack.html">包展开</a>的简单以复制捕获</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 带<a href="cpp-language-initialization.html">初始化器</a>的以复制捕获</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 简单以引用捕获</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 作为<a href="cpp-language-parameter_pack.html">包展开</a>的简单引用捕获</div>
|
|
<div class="t-li1"><span class="t-li">6)</span> 带初始化器的以引用捕获</div>
|
|
<div class="t-li1"><span class="t-li">7)</span> 当前对象的简单以引用捕获</div>
|
|
<div class="t-li1"><span class="t-li">8)</span> 当前对象的简单以复制捕获</div>
|
|
<div class="t-li1"><span class="t-li">9)</span> 用作为包展开的初始化器以复制捕获</div>
|
|
<div class="t-li1"><span class="t-li">10)</span> 用作为包展开的初始化器以引用捕获</div>
|
|
<p>当默认捕获符是 <code>&</code> 时,后继的简单捕获符不能以 <code>&</code> 开始。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> S2 <span class="br0">{</span> <span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span> i<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> S2<span class="sy4">::</span><span class="me2">f</span><span class="br0">(</span><span class="kw4">int</span> i<span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="br0">[</span><span class="sy3">&</span><span class="br0">]</span><span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK:默认以引用捕获</span>
|
|
<span class="br0">[</span><span class="sy3">&</span>, i<span class="br0">]</span><span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK:以引用捕获,但 i 以值捕获</span>
|
|
<span class="br0">[</span><span class="sy3">&</span>, <span class="sy3">&</span>i<span class="br0">]</span> <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 错误:以引用捕获为默认时的以引用捕获</span>
|
|
<span class="br0">[</span><span class="sy3">&</span>, this<span class="br0">]</span> <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK:等价于 [&]</span>
|
|
<span class="br0">[</span><span class="sy3">&</span>, this, i<span class="br0">]</span><span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK:等价于 [&, i]</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>当默认捕获符是 <code>=</code> 时,后继的简单捕获符必须以 <code>&</code> 开始,<span class="t-rev-inl t-since-cxx17"><span>或者为 <code>*this</code></span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span> <span class="t-rev-inl t-since-cxx20"><span>或 <code>this</code></span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> S2 <span class="br0">{</span> <span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span> i<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> S2<span class="sy4">::</span><span class="me2">f</span><span class="br0">(</span><span class="kw4">int</span> i<span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span><span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK:默认以复制捕获</span>
|
|
<span class="br0">[</span><span class="sy1">=</span>, <span class="sy3">&</span>i<span class="br0">]</span><span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK:以复制捕获,但 i 以引用捕获</span>
|
|
<span class="br0">[</span><span class="sy1">=</span>, <span class="sy2">*</span>this<span class="br0">]</span><span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// C++17 前:错误:无效语法</span>
|
|
<span class="co1">// C++17 起:OK:以复制捕获外围的 S2</span>
|
|
<span class="br0">[</span><span class="sy1">=</span>, this<span class="br0">]</span> <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// C++20 前:错误:= 为默认时的 this</span>
|
|
<span class="co1">// C++20 起:OK:同 [=]</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">struct</span> S2 <span class="br0">{</span> <span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span> i<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> S2<span class="sy4">::</span><span class="me2">f</span><span class="br0">(</span><span class="kw4">int</span> i<span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="br0">[</span>i, i<span class="br0">]</span> <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 错误:i 重复</span>
|
|
<span class="br0">[</span>this, <span class="sy2">*</span>this<span class="br0">]</span> <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 错误:"this" 重复 (C++17)</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>只有定义于块作用域或<a href="cpp-language-data_members.html#.E6.88.90.E5.91.98.E5.88.9D.E5.A7.8B.E5.8C.96">默认成员初始化器</a>中的 lambda 表达式能拥有默认捕获符或无初始化器的捕获符。对于这种 lambda 表达式,其<i>可达作用域(reaching scope)</i>定义为其最内层的外围函数(及其形参)内(包含自身)的外围作用域的集合。这其中包含各个嵌套的块作用域,以及当此 lambda 为嵌套的 lambda 时也包含其各个外围 lambda 的作用域。</p>
|
|
<p>(除了 <code>this</code> 捕获符之外的)任何无初始化器的捕获符中的 <span class="t-spar">标识符</span> 会使用通常的<a href="cpp-language-lookup.html">无限定名字查找</a>在 lambda 的<i>可达作用域</i>中查找。查找结果必须是在可达作用域中声明的且具有自动存储期的<a href="cpp-language-object.html">变量</a><span class="t-rev-inl t-since-cxx20"><span>,或对应变量满足这种要求的<a href="cpp-language-structured_binding.html">结构化绑定</a></span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>。该实体被<i>显式捕获</i>。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx14">
|
|
<td>
|
|
<p>带有初始化器的捕获符的行为如同它声明并显式捕获一个以类型 <a href="cpp-language-auto.html">auto</a> 声明的变量,该变量的声明区是 lambda 表达式体(即它不在其初始化器的作用域中),但:</p>
|
|
<ul>
|
|
<li>如果以复制捕获,那么闭包对象的非静态数据成员是指代这个 auto 变量的另一种方式。</li>
|
|
<li>如果以引用捕获,那么引用变量的生存期在闭包对象的生存期结束时结束。</li>
|
|
</ul>
|
|
<p>这可以用于以像 <span class="t-c"><span class="mw-geshi cpp source-cpp">x <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">move</span><span class="br0">(</span>x<span class="br0">)</span></span></span> 这样的捕获符捕获仅可移动的类型。</p>
|
|
<p>这也可以使通过 const 引用进行捕获成为可能,比如以 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">&</span>cr <span class="sy1">=</span> <a href="cpp-utility-as_const.html"><span class="kw1121">std::<span class="me2">as_const</span></span></a><span class="br0">(</span>x<span class="br0">)</span></span></span> 或类似的方式。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">int</span> x <span class="sy1">=</span> <span class="nu0">4</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> y <span class="sy1">=</span> <span class="br0">[</span><span class="sy3">&</span>r <span class="sy1">=</span> x, x <span class="sy1">=</span> x <span class="sy2">+</span> <span class="nu0">1</span><span class="br0">]</span><span class="br0">(</span><span class="br0">)</span><span class="sy2">-</span><span class="sy1">></span><span class="kw4">int</span>
|
|
<span class="br0">{</span>
|
|
r <span class="sy2">+</span><span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span>
|
|
<span class="kw1">return</span> x <span class="sy2">*</span> x<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 更新 ::x 到 6 并初始化 y 为 25。</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>如果捕获符列表具有默认捕获符,且未显式(以 <code>this</code> 或 <code>*this</code>)捕获其外围对象,或任何在 lambda 体内<a href="cpp-language-definition.html#ODR_.E5.BC.8F.E4.BD.BF.E7.94.A8">可 odr 式使用</a>的自动变量<span class="t-rev-inl t-since-cxx20"><span>,或对应变量拥有自动存储期的<a href="cpp-language-structured_binding.html">结构化绑定</a></span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>,那么在以下情况下,它<i>隐式</i>捕获之:</p>
|
|
<ul>
|
|
<li>lambda 体 <a href="cpp-language-definition.html#ODR_.E5.BC.8F.E4.BD.BF.E7.94.A8">ODR 式使用</a>了该实体</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx14">
|
|
<td>
|
|
<ul>
|
|
<li>或者,该实体在<span class="t-rev-inl t-until-cxx17"><span>取决于某个泛型 lambda 形参的</span> <span><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></span></span>表达式内的潜在求值表达式中被指名(包括在使用非静态类成员的前添加隐含的 <span class="t-c"><span class="mw-geshi cpp source-cpp">this<span class="sy2">-</span><span class="sy1">></span></span></span>)。就此目的而言,始终认为 <a href="cpp-language-typeid.html"><code>typeid</code></a> 的操作数被潜在求值。<span class="t-rev-inl t-since-cxx17"><span>即使实体仅在<a href="cpp-language-if.html#constexpr_if">舍弃语句</a>中被指名,它也可能会被隐式捕获。</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span></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="kw4">const</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="sy1">=</span> <span class="br0">{</span><span class="br0">}</span><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><span class="kw4">const</span> <span class="kw4">int</span><span class="sy3">&</span>, <span class="kw4">const</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">1</span><span class="br0">]</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="co1">// #2</span>
|
|
<span class="kw4">void</span> test<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span> x <span class="sy1">=</span> <span class="nu0">17</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> g0 <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> a<span class="br0">)</span> <span class="br0">{</span> f<span class="br0">(</span>x<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK:调用 #1,不捕获 x</span>
|
|
<span class="kw4">auto</span> g1 <span class="sy1">=</span> <span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> a<span class="br0">)</span> <span class="br0">{</span> f<span class="br0">(</span>x<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// C++14 中不捕获 x,C++17 中捕获 x</span>
|
|
<span class="co1">// 捕获能被优化掉</span>
|
|
<span class="kw4">auto</span> g2 <span class="sy1">=</span> <span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> a<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw4">int</span> selector<span class="br0">[</span>sizeof<span class="br0">(</span>a<span class="br0">)</span> <span class="sy1">==</span> <span class="nu0">1</span> <span class="sy4">?</span> <span class="nu0">1</span> <span class="sy4">:</span> <span class="nu0">2</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
f<span class="br0">(</span>x, selector<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK:这是待决表达式,因此 x 被捕获</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> g3 <span class="sy1">=</span> <span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> a<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">typeid</span><span class="br0">(</span>a <span class="sy2">+</span> x<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 捕获 x,不管 a + x 是否为不求值操作数</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>如果 lambda 体 <a href="cpp-language-definition.html#ODR_.E5.BC.8F.E4.BD.BF.E7.94.A8">ODR 式使用</a>了以复制捕获的实体,那么它访问的是闭包类型的成员。如果它未 ODR 式使用该实体,那么访问的是原对象:</p>
|
|
<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">const</span> <span class="kw4">int</span><span class="sy2">*</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> g<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span> N <span class="sy1">=</span> <span class="nu0">10</span><span class="sy4">;</span>
|
|
<span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span><span class="br0">{</span>
|
|
<span class="kw4">int</span> arr<span class="br0">[</span>N<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 非 ODR 式使用:指代 g 的 const int N</span>
|
|
f<span class="br0">(</span><span class="sy3">&</span>N<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// ODR 式使用:导致 N 被(以复制)捕获</span>
|
|
<span class="co1">// &N 是闭包对象的成员 N 的地址,而非 g 中的 N</span>
|
|
<span class="br0">}</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
如果 lambda ODR 式使用了以引用捕获的引用,那么它使用原引用所指代的对象,而非被捕获的引用自身:
|
|
<div class="t-example">
|
|
<div class="t-example-live-link"></div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co2">#include <iostream></span>
|
|
|
|
<span class="kw4">auto</span> make_function<span class="br0">(</span><span class="kw4">int</span><span class="sy3">&</span> x<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> <span class="br0">[</span><span class="sy3">&</span><span class="br0">]</span><span class="br0">{</span> <a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> x <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw4">int</span> i <span class="sy1">=</span> <span class="nu0">3</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> f <span class="sy1">=</span> make_function<span class="br0">(</span>i<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// f 中对 x 的使用直接绑定到 i</span>
|
|
i <span class="sy1">=</span> <span class="nu0">5</span><span class="sy4">;</span>
|
|
f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK;打印 5</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<p>在带默认捕获符 <code>=</code> 的 lambda 体内,任何可捕获对实体的类型为如同它被捕获(从而若 lambda 非 <code>mutable</code> 则通常会加上 const 限定),即使该实体在不求值运算数中且未被捕获(例如在 <a href="cpp-language-decltype.html"><code>decltype</code></a> 中):</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">void</span> f3<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw4">float</span> x, <span class="sy3">&</span>r <span class="sy1">=</span> x<span class="sy4">;</span>
|
|
<span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span>
|
|
<span class="br0">{</span> <span class="co1">// x 与 r 不被捕获(在 decltype 的操作数中出现并不是 ODR 式使用)</span>
|
|
decltype<span class="br0">(</span>x<span class="br0">)</span> y1<span class="sy4">;</span> <span class="co1">// y1 拥有 float 类型</span>
|
|
decltype<span class="br0">(</span><span class="br0">(</span>x<span class="br0">)</span><span class="br0">)</span> y2 <span class="sy1">=</span> y1<span class="sy4">;</span> <span class="co1">// y2 拥有 float const& 类型,因为此 lambda</span>
|
|
<span class="co1">// 非 mutable 且 x 是左值</span>
|
|
decltype<span class="br0">(</span>r<span class="br0">)</span> r1 <span class="sy1">=</span> y1<span class="sy4">;</span> <span class="co1">// r1 拥有 float& 类型(不考虑变换)</span>
|
|
decltype<span class="br0">(</span><span class="br0">(</span>r<span class="br0">)</span><span class="br0">)</span> r2 <span class="sy1">=</span> y2<span class="sy4">;</span> <span class="co1">// r2 拥有 float const& 类型</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>lambda (隐式或显式)捕获的任何实体均被该 lambda 表达式 ODR 式使用(因此嵌套的 lambda 的隐式捕获将触发其外围 lambda 的隐式捕获)。</p>
|
|
<p>所有隐式捕获的变量必须在 lambda 的<i>可达作用域</i>中声明。</p>
|
|
<p>如果 lambda(以 <code>this</code> 或 <code>*this</code>)捕获了其外围对象,那么要么其最接近的外围函数必须是非静态成员函数,要么该 lambda 必须处于某个<a href="cpp-language-data_members.html#.E6.88.90.E5.91.98.E5.88.9D.E5.A7.8B.E5.8C.96">默认成员初始化器</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> s2 <span class="br0">{</span>
|
|
<span class="kw4">double</span> ohseven <span class="sy1">=</span> <span class="nu18">.007</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> f<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="co1">// 以下两个 lambda 的最接近外围函数</span>
|
|
<span class="kw1">return</span> <span class="br0">[</span>this<span class="br0">]</span> <span class="br0">{</span> <span class="co1">// 以引用捕获外围的 s2</span>
|
|
<span class="kw1">return</span> <span class="br0">[</span><span class="sy2">*</span>this<span class="br0">]</span> <span class="br0">{</span> <span class="co1">// 以复制捕获外围的 s2 (C++17)</span>
|
|
<span class="kw1">return</span> ohseven<span class="sy4">;</span> <span class="co1">// OK</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="kw4">auto</span> g<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">{</span> <span class="co1">// 无捕获</span>
|
|
<span class="kw1">return</span> <span class="br0">[</span><span class="sy2">*</span>this<span class="br0">]</span><span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 错误:*this 未被外层 lambda 表达式所捕获</span>
|
|
<span class="br0">}</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>如果 lambda 表达式<span class="t-rev-inl t-since-cxx14"><span>(或泛型 lambda 的函数调用运算符的一个实例化)</span> <span><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></span></span> ODR 式使用了 <code>this</code> 或任何具有自动存储期的变量,那么它必须被该 lambda 表达式所捕获。</p>
|
|
<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> i<span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> <span class="kw4">const</span> N <span class="sy1">=</span> <span class="nu0">20</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> m1 <span class="sy1">=</span> <span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span> <span class="br0">{</span>
|
|
<span class="kw4">int</span> <span class="kw4">const</span> M <span class="sy1">=</span> <span class="nu0">30</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> m2 <span class="sy1">=</span> <span class="br0">[</span>i<span class="br0">]</span> <span class="br0">{</span>
|
|
<span class="kw4">int</span> x<span class="br0">[</span>N<span class="br0">]</span><span class="br0">[</span>M<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// N 与 M 未被 ODR 式使用 </span>
|
|
<span class="co1">// (它们可以不被捕获)</span>
|
|
x<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span> <span class="sy1">=</span> i<span class="sy4">;</span> <span class="co1">// i 被 m2 显式捕获</span>
|
|
<span class="co1">// 并被 m1 隐式捕获</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw1">struct</span> s1 <span class="co1">// f1() 中的局部类</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> f<span class="sy4">;</span>
|
|
<span class="kw4">void</span> work<span class="br0">(</span><span class="kw4">int</span> n<span class="br0">)</span> <span class="co1">// 非静态成员函数</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> m <span class="sy1">=</span> n <span class="sy2">*</span> n<span class="sy4">;</span>
|
|
<span class="kw4">int</span> j <span class="sy1">=</span> <span class="nu0">40</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> m3 <span class="sy1">=</span> <span class="br0">[</span>this, m<span class="br0">]</span> <span class="br0">{</span>
|
|
<span class="kw4">auto</span> m4 <span class="sy1">=</span> <span class="br0">[</span><span class="sy3">&</span>, j<span class="br0">]</span> <span class="br0">{</span> <span class="co1">// 错误:j 未被 m3 捕获</span>
|
|
<span class="kw4">int</span> x <span class="sy1">=</span> n<span class="sy4">;</span> <span class="co1">// 错误:n 被 m4 隐式捕获</span>
|
|
<span class="co1">// 但未被 m3 捕获</span>
|
|
x <span class="sy2">+</span><span class="sy1">=</span> m<span class="sy4">;</span> <span class="co1">// OK:m 被 m4 捕获</span>
|
|
<span class="co1">// 且被 m3 显式捕获</span>
|
|
x <span class="sy2">+</span><span class="sy1">=</span> i<span class="sy4">;</span> <span class="co1">// 错误:i 在可达作用域之外</span>
|
|
<span class="co1">// (该作用域在 work() 结束)</span>
|
|
x <span class="sy2">+</span><span class="sy1">=</span> f<span class="sy4">;</span> <span class="co1">// OK:this 被 m4 隐式捕获</span>
|
|
<span class="co1">// 且被 m3 显式捕获</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>以不带有初始化器的捕获符不能捕获类成员(如上提及,捕获符列表中只能有<a href="cpp-language-object.html">变量</a>):</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">class</span> S <span class="br0">{</span>
|
|
<span class="kw4">int</span> x <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>
|
|
<span class="kw4">int</span> i <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span>
|
|
<span class="co1">// auto l1 = [i, x]{ use(i, x); }; // 错误:x 不是变量</span>
|
|
<span class="kw4">auto</span> l2 <span class="sy1">=</span> <span class="br0">[</span>i, x<span class="sy1">=</span>x<span class="br0">]</span><span class="br0">{</span> use<span class="br0">(</span>i, x<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK,复制捕获</span>
|
|
i <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> x <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> l2<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 use(0,0)</span>
|
|
<span class="kw4">auto</span> l3 <span class="sy1">=</span> <span class="br0">[</span>i, <span class="sy3">&</span>x<span class="sy1">=</span>x<span class="br0">]</span><span class="br0">{</span> use<span class="br0">(</span>i, x<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK,引用捕获</span>
|
|
i <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> x <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> l3<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 use(1,2)</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>当 lambda 用隐式的以复制捕获捕获某个成员时,它并不产生该成员变量的副本:对成员变量 <code>m</code> 的使用被处理成表达式 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="br0">(</span><span class="sy2">*</span>this<span class="br0">)</span>.<span class="me1">m</span></span></span>,而 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy2">*</span>this</span></span> 始终被隐式以引用捕获:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">class</span> S <span class="br0">{</span>
|
|
<span class="kw4">int</span> x <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>
|
|
<span class="kw4">int</span> i <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> l1 <span class="sy1">=</span> <span class="br0">[</span><span class="sy1">=</span><span class="br0">]</span><span class="br0">{</span> use<span class="br0">(</span>i, x<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 捕获 i 的副本和 this 指针的副本</span>
|
|
i <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> x <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> l1<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 use(0,1),如同 i 以复制而 x 以引用捕获</span>
|
|
<span class="kw4">auto</span> l2 <span class="sy1">=</span> <span class="br0">[</span>i, this<span class="br0">]</span><span class="br0">{</span> use<span class="br0">(</span>i, x<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 同上,改为显式捕获</span>
|
|
i <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> x <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> l2<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 use(1,2),如同 i 以复制而 x 以引用捕获</span>
|
|
<span class="kw4">auto</span> l3 <span class="sy1">=</span> <span class="br0">[</span><span class="sy3">&</span><span class="br0">]</span><span class="br0">{</span> use<span class="br0">(</span>i, x<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 以引用捕获 i,并捕获 this 指针的副本</span>
|
|
i <span class="sy1">=</span> <span class="nu0">3</span><span class="sy4">;</span> x <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> l3<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 use(3,2),如同 i 与 x 均以引用捕获</span>
|
|
<span class="kw4">auto</span> l4 <span class="sy1">=</span> <span class="br0">[</span>i, <span class="sy2">*</span>this<span class="br0">]</span><span class="br0">{</span> use<span class="br0">(</span>i, x<span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 制造 *this 的副本,包含 x 的副本</span>
|
|
i <span class="sy1">=</span> <span class="nu0">4</span><span class="sy4">;</span> x <span class="sy1">=</span> <span class="nu0">4</span><span class="sy4">;</span> l4<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 use(3,2),如同 i 与 x 均以复制捕获</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>如果 lambda 表达式在<a href="cpp-language-default_arguments.html">默认实参</a>中出现,那么它不能显式或隐式捕获任何变量。</p>
|
|
<p>不能捕获<a href="cpp-language-union.html">匿名联合体</a>的成员。只能以复制捕获<a href="cpp-language-bit_field.html">位域</a>。</p>
|
|
<p>如果嵌套的 lambda <code>m2</code> 捕获了也被其直接外围 lambda <code>m1</code> 所捕获的实体,那么以如下方式将 <code>m2</code> 的捕获进行变换:</p>
|
|
<ul>
|
|
<li>如果外围 lambda <code>m1</code> 以复制捕获,那么 <code>m2</code> 捕获 <code>m1</code> 的闭包类型的非静态成员,而非原变量或 <code>this</code>。</li>
|
|
<li>如果外围 lambda <code>m1</code> 以引用捕获,那么 <code>m2</code> 捕获原变量或 <code>this</code>。</li>
|
|
</ul>
|
|
<div class="t-example">
|
|
<div class="t-example-live-link"></div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co2">#include <iostream></span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> a <span class="sy1">=</span> <span class="nu0">1</span>, b <span class="sy1">=</span> <span class="nu0">1</span>, c <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">auto</span> m1 <span class="sy1">=</span> <span class="br0">[</span>a, <span class="sy3">&</span>b, <span class="sy3">&</span>c<span class="br0">]</span><span class="br0">(</span><span class="br0">)</span> mutable <span class="br0">{</span>
|
|
<span class="kw4">auto</span> m2 <span class="sy1">=</span> <span class="br0">[</span>a, b, <span class="sy3">&</span>c<span class="br0">]</span><span class="br0">(</span><span class="br0">)</span> mutable <span class="br0">{</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> a <span class="sy1"><<</span> b <span class="sy1"><<</span> c <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
a <span class="sy1">=</span> <span class="nu0">4</span><span class="sy4">;</span> b <span class="sy1">=</span> <span class="nu0">4</span><span class="sy4">;</span> c <span class="sy1">=</span> <span class="nu0">4</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
a <span class="sy1">=</span> <span class="nu0">3</span><span class="sy4">;</span> b <span class="sy1">=</span> <span class="nu0">3</span><span class="sy4">;</span> c <span class="sy1">=</span> <span class="nu0">3</span><span class="sy4">;</span>
|
|
m2<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
a <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> b <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> c <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span>
|
|
|
|
m1<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 m2() 并打印 123</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> a <span class="sy1"><<</span> b <span class="sy1"><<</span> c <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="co1">// 打印 234</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E7.A4.BA.E4.BE.8B">示例</span></h3>
|
|
<div class="t-example">
|
|
<p>此示例演示如何传递 lambda 给泛型算法,以及 lambda 表达式所产生的对象能如何存储于 <span class="t-lc"><a href="cpp-utility-functional-function.html">std::function</a></span> 对象。</p>
|
|
<div class="t-example-live-link"></div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co2">#include <vector></span>
|
|
<span class="co2">#include <iostream></span>
|
|
<span class="co2">#include <algorithm></span>
|
|
<span class="co2">#include <functional></span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<a href="cpp-container-vector.html"><span class="kw1269">std::<span class="me2">vector</span></span></a><span class="sy1"><</span><span class="kw4">int</span><span class="sy1">></span> c <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span>, <span class="nu0">4</span>, <span class="nu0">5</span>, <span class="nu0">6</span>, <span class="nu0">7</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> x <span class="sy1">=</span> <span class="nu0">5</span><span class="sy4">;</span>
|
|
c.<span class="me1">erase</span><span class="br0">(</span><a href="cpp-algorithm-remove.html"><span class="kw1592">std::<span class="me2">remove_if</span></span></a><span class="br0">(</span>c.<span class="me1">begin</span><span class="br0">(</span><span class="br0">)</span>, c.<span class="me1">end</span><span class="br0">(</span><span class="br0">)</span>, <span class="br0">[</span>x<span class="br0">]</span><span class="br0">(</span><span class="kw4">int</span> n<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> n <span class="sy1"><</span> x<span class="sy4">;</span> <span class="br0">}</span><span class="br0">)</span>, c.<span class="me1">end</span><span class="br0">(</span><span class="br0">)</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> <span class="st0">"c: "</span><span class="sy4">;</span>
|
|
<a href="cpp-algorithm-for_each.html"><span class="kw1568">std::<span class="me2">for_each</span></span></a><span class="br0">(</span>c.<span class="me1">begin</span><span class="br0">(</span><span class="br0">)</span>, c.<span class="me1">end</span><span class="br0">(</span><span class="br0">)</span>, <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">int</span> i<span class="br0">)</span><span class="br0">{</span> <a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> i <span class="sy1"><<</span> <span class="st0">' '</span><span class="sy4">;</span> <span class="br0">}</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> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 闭包的类型不能被指名,但可用 auto 提及</span>
|
|
<span class="co1">// C++14 起,lambda 可以有默认实参</span>
|
|
<span class="kw4">auto</span> func1 <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">int</span> i <span class="sy1">=</span> <span class="nu0">6</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> i <span class="sy2">+</span> <span class="nu0">4</span><span class="sy4">;</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> <span class="st0">"func1: "</span> <span class="sy1"><<</span> func1<span class="br0">(</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 与所有可调用对象相同,闭包能可以被捕获到 std::function 之中</span>
|
|
<span class="co1">// (这可能带来不必要的开销)</span>
|
|
<a href="cpp-utility-functional-function.html"><span class="kw1059">std::<span class="me2">function</span></span></a><span class="sy1"><</span><span class="kw4">int</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy1">></span> func2 <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">int</span> i<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> i <span class="sy2">+</span> <span class="nu0">4</span><span class="sy4">;</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> <span class="st0">"func2: "</span> <span class="sy1"><<</span> func2<span class="br0">(</span><span class="nu0">6</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</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> <span class="st0">"模仿递归 lambda 调用:<span class="es1">\n</span>斐波那契数:"</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> nth_fibonacci <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">int</span> n<span class="br0">)</span> <span class="br0">{</span>
|
|
<a href="cpp-utility-functional-function.html"><span class="kw1059">std::<span class="me2">function</span></span></a><span class="sy1"><</span><span class="kw4">int</span><span class="br0">(</span><span class="kw4">int</span>,<span class="kw4">int</span>,<span class="kw4">int</span><span class="br0">)</span><span class="sy1">></span> fib <span class="sy1">=</span> <span class="br0">[</span><span class="sy3">&</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">int</span> a, <span class="kw4">int</span> b, <span class="kw4">int</span> n<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> n <span class="sy4">?</span> fib<span class="br0">(</span>a <span class="sy2">+</span> b, a, n <span class="sy2">-</span> <span class="nu0">1</span><span class="br0">)</span> <span class="sy4">:</span> b<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">return</span> fib<span class="br0">(</span><span class="nu0">1</span>, <span class="nu0">0</span>, n<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">for</span> <span class="br0">(</span><span class="kw4">int</span> i<span class="br0">{</span><span class="nu0">1</span><span class="br0">}</span><span class="sy4">;</span> i <span class="sy3">!</span><span class="sy1">=</span> <span class="nu0">9</span><span class="sy4">;</span> <span class="sy2">++</span>i<span class="br0">)</span> <span class="br0">{</span> <a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> nth_fibonacci<span class="br0">(</span>i<span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">", "</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"<span class="es1">\n</span>另一种 lambda 递归方案:<span class="es1">\n</span>斐波那契数:"</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> nth_fibonacci2 <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">int</span> n<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw4">auto</span> fib <span class="sy1">=</span> <span class="br0">[</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">auto</span> self, <span class="kw4">int</span> a, <span class="kw4">int</span> b, <span class="kw4">int</span> n<span class="br0">)</span> <span class="sy2">-</span><span class="sy1">></span> <span class="kw4">int</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> n <span class="sy4">?</span> self<span class="br0">(</span>self, a <span class="sy2">+</span> b, a, n <span class="sy2">-</span> <span class="nu0">1</span><span class="br0">)</span> <span class="sy4">:</span> b<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">return</span> fib<span class="br0">(</span>fib, <span class="nu0">1</span>, <span class="nu0">0</span>, n<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">for</span> <span class="br0">(</span><span class="kw4">int</span> i<span class="br0">{</span><span class="nu0">1</span><span class="br0">}</span><span class="sy4">;</span> i <span class="sy3">!</span><span class="sy1">=</span> <span class="nu0">9</span><span class="sy4">;</span> <span class="sy2">++</span>i<span class="br0">)</span> <span class="br0">{</span> <a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> nth_fibonacci2<span class="br0">(</span>i<span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">", "</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>输出:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="text source-text">
|
|
<pre class="de1">c: 5 6 7
|
|
func1: 10
|
|
func2: 10
|
|
模仿递归 lambda 调用:
|
|
斐波那契数:1, 1, 2, 3, 5, 8, 13, 21,
|
|
另一种 lambda 递归方案:
|
|
斐波那契数:1, 1, 2, 3, 5, 8, 13, 21,</pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E7.BC.BA.E9.99.B7.E6.8A.A5.E5.91.8A">缺陷报告</span></h3>
|
|
<p>下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。</p>
|
|
<table class="dsctable" style="font-size:0.8em">
|
|
<tr>
|
|
<th>DR</th>
|
|
<th>应用于</th>
|
|
<th>出版时的行为</th>
|
|
<th>正确行为</th>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue974">CWG 974</a></td>
|
|
<td>C++11</td>
|
|
<td>lambda 表达式的形参列表中不能有默认实参</td>
|
|
<td>允许</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue975">CWG 975</a></td>
|
|
<td>C++11</td>
|
|
<td>只有在 lambda 体含有单条 return 语句时<br />
|
|
才推导闭包的 <code>operator()</code> 的返回类型</td>
|
|
<td>如同对于 C++14 返回 auto 的函数一般推导</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1722">CWG 1722</a></td>
|
|
<td>C++11</td>
|
|
<td>无捕获的 lambda 的转换函数的异常说明未指明</td>
|
|
<td>转换函数为 noexcept</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1891">CWG 1891</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">
|
|
<tr class="t-dsc">
|
|
<td><a href="cpp-language-auto.html"><code>auto</code> 说明符</a><span class="t-mark-rev t-since-cxx11">(C++11)</span></td>
|
|
<td>指定从表达式推导的类型</td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td>
|
|
<div class="t-dsc-member-div">
|
|
<div><a href="cpp-utility-functional-function.html"><span class="t-lines"><span>function</span></span></a></div>
|
|
<div><span class="t-lines"><span><span class="t-mark-rev t-since-cxx11">(C++11)</span></span></span></div>
|
|
</div>
|
|
</td>
|
|
<td>包装具有指定函数调用签名的任意可复制构造类型的可调用对象<br />
|
|
<span class="t-mark">(类模板)</span></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|