{"id":1401,"date":"2023-09-29T02:09:10","date_gmt":"2023-09-28T17:09:10","guid":{"rendered":"https:\/\/xn--k10aa.com\/?p=1401"},"modified":"2024-10-19T23:09:34","modified_gmt":"2024-10-19T14:09:34","slug":"c-lambda-note","status":"publish","type":"post","link":"https:\/\/remoooo.com\/en\/c-lambda-note\/","title":{"rendered":"C++ Lambda Note"},"content":{"rendered":"<p>I am also a rookie QAQ, so I will share my notes on learning C++ Lambda. This is just like a glimpse of the big guys on Zhihu exploring the vast world of wisdom through a narrow slit. If I make any mistakes, please correct me.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Lambda expressions are introduced in the C++11 standard and allow anonymous functions to be defined in code. Each chapter of this article will have a large number of code examples to help you understand. Some of the code in this article refers to <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/cpp\/lambda-expressions-in-cpp?view=msvc-170&amp;source=docs\">Microsoft official documentation | Lambda expressions in C++ | Microsoft Learn<\/a>.<\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">Table of contents<\/h2>\n\n\n\n<p><strong>Basics<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>1. Lambda Basic Syntax<\/li>\n\n\n\n<li>2. How to use Lambda expressions<\/li>\n\n\n\n<li>3. Detailed discussion of capture lists<\/li>\n\n\n\n<li>4. mutable keyword<\/li>\n\n\n\n<li>5. Lambda return value deduction<\/li>\n\n\n\n<li>6. Nested Lambda<\/li>\n\n\n\n<li>7. Lambda, std:function and delegates<\/li>\n\n\n\n<li>8. Lambda in asynchronous and concurrent programming<\/li>\n\n\n\n<li>9. Generic Lambda (C++14)<ol start=\"10\"><li>Lambda Scope<\/li><\/ol>\n<ol class=\"wp-block-list\" start=\"11\">\n<li>practice<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n\n\n\n<p><strong>Intermediate<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>1. Lambda&#039;s underlying implementation<\/li>\n\n\n\n<li>2. Lambda type, decltype and conditional compilation<\/li>\n\n\n\n<li>3. Lambda\u2019s evolution in the new standard<\/li>\n\n\n\n<li>4. State-preserving Lambda<\/li>\n\n\n\n<li>5. Optimization and Lambda<\/li>\n\n\n\n<li>6. Integration with other programming paradigms<\/li>\n\n\n\n<li>7. Lambda and Exception Handling<\/li>\n<\/ul>\n\n\n\n<p><strong>Advanced<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>1. Lambda and noexcept<\/li>\n\n\n\n<li>2. Template parameters in Lambda (C++20 feature)<\/li>\n\n\n\n<li>3. Lambda Reflection<\/li>\n\n\n\n<li>4. Cross-platform and ABI issues<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Basics<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Lambda Basic Syntax<\/h3>\n\n\n\n<p>Lambda basically looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>[ capture_clause ] ( parameters ) -&gt; return_type { \/\/ function_body }<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Capture clause (<strong>capture_clause<\/strong>) determines which variables in the outer scope will be captured by this lambda and how they will be captured (by value, by reference, or not captured). We discuss capture clauses in detail in the next chapter.<\/li>\n\n\n\n<li>Parameter list (<strong>parameters<\/strong>) and the function body (<strong>function_body<\/strong>) is the same as a normal function, there is no difference.<\/li>\n\n\n\n<li>Return Type (<strong>return_type<\/strong>) is slightly different. If the function body contains multiple statements and needs to return a value, the return type must be explicitly specified, unless all return statements return the same type, in which case the return type can be inferred automatically.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">2. How to use Lambda expressions<\/h3>\n\n\n\n<p>Syntax example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u4e00\u4e2a\u4e0d\u6355\u83b7\u4efb\u4f55\u5916\u90e8\u53d8\u91cf\u3001\u4e0d\u63a5\u53d7\u53c2\u6570\u3001\u6ca1\u6709\u8fd4\u56de\u503c\u7684lambda\nauto greet = &#91;] { std::cout &lt;&lt; \"Hello, World!\" &lt;&lt; std::endl; };\n\n\/\/ \u4e00\u4e2a\u901a\u8fc7\u5f15\u7528\u6355\u83b7\u5916\u90e8\u53d8\u91cf\u3001\u63a5\u53d7\u4e00\u4e2aint\u53c2\u6570\u3001\u8fd4\u56deint\u7c7b\u578b\u7684lambda\nint x = 42;\nauto add_to_x = &#91;&amp;x](int y) -&gt; int { return x + y; };\n\n\/\/ \u4e00\u4e2a\u901a\u8fc7\u503c\u6355\u83b7\u6240\u6709\u5916\u90e8\u53d8\u91cf\u3001\u63a5\u53d7\u4e24\u4e2a\u53c2\u6570\u3001\u8fd4\u56de\u7c7b\u578b\u88ab\u81ea\u52a8\u63a8\u65ad\u7684lambda\nint a = 1, b = 2;\nauto sum = &#91;=](int x, int y) { return a + b + x + y; };\n\n\/\/ \u4f7f\u7528\u521d\u59cb\u5316\u6355\u83b7\u521b\u5efa\u65b0\u53d8\u91cf\u7684lambda\uff08C++14\u7279\u6027\uff09\nauto multiply = &#91;product = a * b](int scalar) { return product * scalar; };<\/code><\/pre>\n\n\n\n<p>Practical example:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>As a sorting criterion<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u4f5c\u4e3a\u6392\u5e8f\u51c6\u5219\n#include &lt;algorithm&gt;\n#include &lt;vector&gt;\n#include &lt;iostream&gt;\n\nint main() {\n    std::vector&lt;int&gt; v{4, 1, 3, 5, 2};\n    std::sort(v.begin(), v.end(), &#91;](int a, int b) {\n        return a &lt; b; \/\/ \u5347\u5e8f\u6392\u5217\n    });\n\n    for (int i : v) {\n        std::cout &lt;&lt; i &lt;&lt; ' ';\n    }\n    \/\/ \u8f93\u51fa\uff1a1 2 3 4 5\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>For forEach operation<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;vector&gt;\n#include &lt;iostream&gt;\n#include &lt;algorithm&gt;\n\nint main() {\n    std::vector&lt;int&gt; v{1, 2, 3, 4, 5};\n    std::for_each(v.begin(), v.end(), &#91;](int i) {\n        std::cout &lt;&lt; i * i &lt;&lt; ' '; \/\/ \u6253\u5370\u6bcf\u4e2a\u6570\u5b57\u7684\u5e73\u65b9\n    });\n    \/\/ \u8f93\u51fa\uff1a1 4 9 16 25\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>For cumulative functions<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;vector&gt;\n#include &lt;numeric&gt;\n\nint main() {\n    std::vector&lt;int&gt; v{1, 2, 3, 4, 5};\n    int sum = std::accumulate(v.begin(), v.end(), 0, &#91;](int a, int b) {\n        return a + b; \/\/ \u6c42\u548c\n    });\n\n    std::cout &lt;&lt; sum &lt;&lt; std::endl; \/\/ \u8f93\u51fa\uff1a15\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>For thread constructor<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;thread&gt;\n#include &lt;iostream&gt;\n\nint main() {\n    int x = 10;\n    std::thread t(&#91;x]() {\n        std::cout &lt;&lt; \"Value in thread: \" &lt;&lt; x &lt;&lt; std::endl;\n    });\n    t.join(); \/\/ \u8f93\u51fa\uff1aValue in thread: 10\n    \/\/ \u6ce8\u610f\uff1a\u7ebf\u7a0b\u4e2d\u4f7f\u7528\u7684x\u662f\u5728\u521b\u5efa\u7ebf\u7a0b\u65f6\u6309\u503c\u6355\u83b7\u7684\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3. Detailed discussion of the capture list<\/h3>\n\n\n\n<p>The capture list is optional. It specifies the external variables that can be accessed from within the lambda expression. Referenced external variables can be modified from within the lambda expression, but external variables captured by value cannot be modified, that is, variables prefixed with an ampersand (&amp;) are accessed by reference, and variables without the prefix are accessed by value.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Do not capture any external variables<\/strong>:<\/li>\n<\/ol>\n\n\n\n<p>cpp []{ \/<em>\u2026<\/em>\/ }<\/p>\n\n\n\n<p>This lambda does not capture any variables from the outer scope.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>By default, all external variables are captured (by reference)<\/strong>:<\/li>\n<\/ol>\n\n\n\n<p>cpp [&amp;]{ \/<em>\u2026<\/em>\/ }<\/p>\n\n\n\n<p>This lambda captures all variables in the outer scope and captures them by reference. If the captured variables are destroyed or out of scope when the lambda is called, undefined behavior occurs.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>By default, all external variables are captured (by value)<\/strong>:<\/li>\n<\/ol>\n\n\n\n<p>cpp[=]{ \/<em>\u2026<\/em>\/ }<\/p>\n\n\n\n<p>This lambda captures all outer scope variables by value, which means it uses a copy of the variables.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Explicitly capture specific variables (by value)<\/strong>:<\/li>\n<\/ol>\n\n\n\n<p>cpp [x]{ \/<em>\u2026<\/em>\/ }<\/p>\n\n\n\n<p>This lambda captures the outer variable x by value.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Explicitly capture specific variables (by reference)<\/strong>:<\/li>\n<\/ol>\n\n\n\n<p>cpp [&amp;x]{ \/<em>\u2026<\/em>\/ }<\/p>\n\n\n\n<p>This lambda captures the outer variable x by reference.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Mixed capture (by value and by reference)<\/strong>:<\/li>\n<\/ol>\n\n\n\n<p>cpp [x, &amp;y]{ \/<em>\u2026<\/em>\/ }<\/p>\n\n\n\n<p>This lambda captures the variable x by value and the variable y by reference.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>By default, variables are captured by value, but some variables are captured by reference.<\/strong>:<\/li>\n<\/ol>\n\n\n\n<p>cpp [=, &amp;x, &amp;y]{ \/<em>\u2026<\/em>\/ }<\/p>\n\n\n\n<p>This lambda captures all outer variables by value by default, but captures variables x and y by reference.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>By default, variables are captured by reference, but some are captured by value.<\/strong>:<\/li>\n<\/ol>\n\n\n\n<p>cpp [&amp;, x, y]{ \/<em>\u2026<\/em>\/ }<\/p>\n\n\n\n<p>This lambda captures all outer variables by reference by default, but captures variables x and y by value.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Capturing the this pointer<\/strong>:<\/li>\n<\/ol>\n\n\n\n<p>cpp [this]{ \/<em>\u2026<\/em>\/ }<\/p>\n\n\n\n<p>This allows the lambda expression to capture the this pointer of the class member function, thus giving access to the class&#039;s member variables and functions.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Capture with initializer expression (since C++14) \u2013 Generic lambda capture<\/strong>:cpp [x = 42]{ \/<em>\u2026<\/em>\/ } creates an anonymous variable x inside the lambda, which can be used in the lambda function body. This is quite useful, for example, you can directly transfer std::unique_ptr with move semantics, which is discussed in detail in the &quot;reference&quot; below.<\/li>\n\n\n\n<li><strong>Capturing the asterisk this (since C++17)<\/strong>:cpp [<em>this]{ \/<\/em>\u2026*\/ } This lambda captures the current object (the instance of its class) by value. This avoids the risk of the this pointer becoming a dangling pointer during the lambda&#039;s lifetime. Before C++17, you could get this by reference, but this had a potential memory risk, that is, if the lifetime of this ended, it would cause a memory leak. Using the asterisk this is equivalent to making a deep copy of the current object.<\/li>\n<\/ol>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>std::unique_ptr is a smart pointer with exclusive ownership. Its original design is to ensure that only one entity can own the object at a time. Therefore, std::unique_ptr cannot be copied, but can only be moved. If you want to capture by value, the compiler will report an error. If you capture by reference, the compiler will not report an error. But there are potential problems. I can think of three:<\/p>\n<\/blockquote>\n\n\n\n<ol class=\"wp-block-list\">\n<li>The life of std::unique_ptr ends before lambda. In this case, accessing this destroyed std::unique_ptr from within lambda will cause the program to crash.<\/li>\n\n\n\n<li>If std::unique_ptr is moved after capture, the reference in the lambda is null, causing the program to crash.<\/li>\n\n\n\n<li>In a multi-threaded environment, the above two problems will occur more frequently. To avoid these problems, you can consider value capture, that is, explicitly use std::move to transfer ownership. In a multi-threaded environment, lock.<\/li>\n<\/ol>\n\n\n\n<p>Code example:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Using Lambda as callback function \u2013 This example also involves function()<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;functional&gt;\n\n\/\/ \u5047\u8bbe\u6709\u4e00\u4e2a\u51fd\u6570\uff0c\u5b83\u5728\u67d0\u4e2a\u64cd\u4f5c\u5b8c\u6210\u540e\u8c03\u7528\u56de\u8c03\u51fd\u6570\nvoid performOperationAsync(std::function&lt;void(int)&gt; callback) {\n    \/\/ \u5f02\u6b65\u64cd\u4f5c...\n    int result = 42; \/\/ \u5047\u8bbe\u8fd9\u662f\u5f02\u6b65\u64cd\u4f5c\u7684\u7ed3\u679c\n    callback(result); \/\/ \u8c03\u7528\u56de\u8c03\u51fd\u6570\n}\n\nint main() {\n    int capture = 100;\n    performOperationAsync(&#91;capture](int result) {\n        std::cout &lt;&lt; \"Async operation result: \" &lt;&lt; result\n                  &lt;&lt; \" with captured value: \" &lt;&lt; capture &lt;&lt; std::endl;\n    });\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"2\">\n<li>Used with smart pointers \u2013 This example also involves the mutable keyword<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;memory&gt;\n\nvoid processResource(std::unique_ptr&lt;int&gt; ptr) {\n    \/\/ \u505a\u4e00\u4e9b\u5904\u7406\n    std::cout &lt;&lt; \"Processing resource with value \" &lt;&lt; *ptr &lt;&lt; std::endl;\n}\n\nint main() {\n    auto ptr = std::make_unique&lt;int&gt;(10);\n\n    \/\/ \u4f7f\u7528Lambda\u5ef6\u8fdf\u8d44\u6e90\u5904\u7406\n    auto deferredProcess = &#91;p = std::move(ptr)]() {\n        processResource(std::move(p));\n    };\n\n    \/\/ \u505a\u4e00\u4e9b\u5176\u4ed6\u64cd\u4f5c...\n    \/\/ ...\n\n    deferredProcess(); \/\/ \u6700\u7ec8\u5904\u7406\u8d44\u6e90\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"3\">\n<li>Synchronizing data access in multiple threads<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>int main() {\n    std::vector&lt;int&gt; data;\n    std::mutex data_mutex;\n    std::vector&lt;std::thread&gt; threadsPool;\n\n    \/\/ Lambda\u7528\u4e8e\u6dfb\u52a0\u6570\u636e\u5230vector\uff0c\u786e\u4fdd\u7ebf\u7a0b\u5b89\u5168\n    auto addData = &#91;&amp;](int value) {\n        std::lock_guard&lt;std::mutex&gt; lock(data_mutex);\n        data.push_back(value);\n        std::cout &lt;&lt; \"Added \" &lt;&lt; value &lt;&lt; \" to the data structure.\" &lt;&lt; std::endl;\n    };\n\n    threadsPool.reserve(10);\n    for (int i = 0; i &lt; 10; ++i) {\n        threadsPool.emplace_back(addData, i);\n    }\n\n    \/\/ \u7b49\u5f85\u6240\u6709\u7ebf\u7a0b\u5b8c\u6210\n    for (auto&amp; thread : threadsPool) {\n        thread.join();\n    }\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"4\">\n<li>Application of Lambda in range query<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;algorithm&gt;\n\nint main() {\n    std::vector&lt;int&gt; v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};\n    int lower_bound = 3;\n    int upper_bound = 7;\n\n    \/\/ \u4f7f\u7528Lambda\u627e\u5230\u7279\u5b9a\u8303\u56f4\u5185\u7684\u6240\u6709\u6570\n    auto range_begin = std::find_if(v.begin(), v.end(), &#91;lower_bound](int x) { return x &gt;= lower_bound; });\n    auto range_end = std::find_if(range_begin, v.end(), &#91;upper_bound](int x) { return x &gt; upper_bound; });\n\n    std::cout &lt;&lt; \"Range: \";\n    std::for_each(range_begin, range_end, &#91;](int x) { std::cout &lt;&lt; x &lt;&lt; ' '; });\n    std::cout &lt;&lt; std::endl;\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"5\">\n<li>Delayed execution<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;chrono&gt;\n\n\/\/ \u6a21\u62df\u4e00\u4e2a\u53ef\u80fd\u9700\u8981\u8017\u65f6\u7684\u64cd\u4f5c\nvoid expensiveOperation(int data) {\n    \/\/ \u6a21\u62df\u8017\u65f6\u64cd\u4f5c\n    std::this_thread::sleep_for(std::chrono::seconds(1));\n    std::cout &lt;&lt; \"Processed data: \" &lt;&lt; data &lt;&lt; std::endl;\n}\n\nint main() {\n    std::vector&lt;std::function&lt;void()&gt;&gt; deferredOperations;\n\n    deferredOperations.reserve(10);\n    \/\/ \u5047\u8bbe\u8fd9\u662f\u4e00\u4e2a\u9700\u8981\u6267\u884c\u8017\u65f6\u64cd\u4f5c\u7684\u5faa\u73af\uff0c\u4f46\u6211\u4eec\u4e0d\u60f3\u7acb\u5373\u6267\u884c\u5b83\u4eec\n    for (int i = 0; i &lt; 10; ++i) {\n        \/\/ \u6355\u83b7i\u5e76\u5ef6\u8fdf\u6267\u884c\n        deferredOperations.emplace_back(&#91;i] {\n            expensiveOperation(i);\n        });\n    }\n\n    std::cout &lt;&lt; \"All operations have been scheduled, doing other work now.\" &lt;&lt; std::endl;\n\n    \/\/ \u5047\u8bbe\u73b0\u5728\u662f\u4e00\u4e2a\u8f83\u597d\u7684\u65f6\u95f4\u70b9\u53bb\u6267\u884c\u8fd9\u4e9b\u8017\u65f6\u7684\u64cd\u4f5c\n    for (auto&amp; operation : deferredOperations) {\n        \/\/ \u5728\u4e00\u4e2a\u65b0\u7ebf\u7a0b\u4e0a\u6267\u884cLambda\u8868\u8fbe\u5f0f\u4ee5\u907f\u514d\u963b\u585e\u4e3b\u7ebf\u7a0b\n        std::thread(operation).detach();\n    }\n\n    \/\/ \u7ed9\u7ebf\u7a0b\u4e00\u4e9b\u65f6\u95f4\u6765\u5904\u7406\u64cd\u4f5c\n    std::this_thread::sleep_for(std::chrono::seconds(2));\n    std::cout &lt;&lt; \"Main thread finished.\" &lt;&lt; std::endl;\n}\n\/* \u6ce8\u610f\uff1a\u5728\u5b9e\u9645\u7684\u591a\u7ebf\u7a0b\u7a0b\u5e8f\u4e2d\uff0c\u901a\u5e38\u9700\u8981\u8003\u8651\u7ebf\u7a0b\u540c\u6b65\u548c\u8d44\u6e90\u7ba1\u7406\n\uff0c\u4f8b\u5982\u4f7f\u7528 std::async \u800c\u4e0d\u662f std::thread().detach()\uff0c\n\u4ee5\u53ca\u4f7f\u7528\u9002\u5f53\u7684\u540c\u6b65\u673a\u5236\u5982\u4e92\u65a5\u9501\u548c\u6761\u4ef6\u53d8\u91cf\u6765\u4fdd\u8bc1\u7ebf\u7a0b\u5b89\u5168\u3002\n\u5728\u8fd9\u4e2a\u7b80\u5316\u7684\u4f8b\u5b50\u4e2d\uff0c\u4e3a\u4e86\u4fdd\u6301\u6e05\u6670\u548c\u96c6\u4e2d\u5728\u5ef6\u8fdf\u64cd\u4f5c\u4e0a\uff0c\n\u8fd9\u4e9b\u7ec6\u8282\u88ab\u7701\u7565\u4e86\u3002*\/\n\n\/\/ \u4e0b\u9762\u6f14\u793a\u8fd9\u4e2a\u4f8b\u5b50\u66f4\u5408\u7406\u7684\u7248\u672c\n\n#include &lt;iostream&gt;\n#include &lt;vector&gt;\n#include &lt;future&gt;\n#include &lt;chrono&gt;\n\/\/ \u6a21\u62df\u4e00\u4e2a\u53ef\u80fd\u9700\u8981\u8017\u65f6\u7684\u64cd\u4f5c\nint expensiveOperation(int data) {\n    \/\/ \u6a21\u62df\u8017\u65f6\u64cd\u4f5c\n    std::this_thread::sleep_for(std::chrono::seconds(1));\n    return data * data; \/\/ \u8fd4\u56de\u4e00\u4e9b\u5904\u7406\u7ed3\u679c\n}\nint main() {\n    std::vector&lt;std::future&lt;int&gt;&gt; deferredResults;\n    \/\/ \u542f\u52a8\u591a\u4e2a\u5f02\u6b65\u4efb\u52a1\n    deferredResults.reserve(10);\n    for (int i = 0; i &lt; 10; ++i) {\n        deferredResults.emplace_back(\n            std::async(std::launch::async, expensiveOperation, i)\n        );\n    }\n    std::cout &lt;&lt; \"All operations have been scheduled, doing other work now.\" &lt;&lt; std::endl;\n    \/\/ \u83b7\u53d6\u5f02\u6b65\u4efb\u52a1\u7684\u7ed3\u679c\n    for (auto&amp; future : deferredResults) {\n        \/\/ get() \u4f1a\u963b\u585e\u76f4\u5230\u5f02\u6b65\u64cd\u4f5c\u5b8c\u6210\u5e76\u8fd4\u56de\u7ed3\u679c\n        std::cout &lt;&lt; \"Processed data: \" &lt;&lt; future.get() &lt;&lt; std::endl;\n    }\n    std::cout &lt;&lt; \"Main thread finished.\" &lt;&lt; std::endl;\n}\n\/* \u5907\u6ce8\uff1astd::async \u4e3a\u6211\u4eec\u7ba1\u7406\u4e86\u8fd9\u4e00\u5207\u3002\n\u6211\u4eec\u4e5f\u4e0d\u9700\u8981\u4f7f\u7528\u4e92\u65a5\u9501\u6216\u5176\u4ed6\u540c\u6b65\u673a\u5236\uff0c\u56e0\u4e3a\u6bcf\u4e2a\u5f02\u6b65\u64cd\u4f5c\u90fd\u5728\u5b83\u81ea\u5df1\u7684\u7ebf\u7a0b\u4e0a\u8fd0\u884c\uff0c\n\u4e0d\u4f1a\u4e92\u76f8\u5e72\u6270\uff0c\u5e76\u4e14\u8fd4\u56de\u7684 future \u5bf9\u8c61\u4e3a\u6211\u4eec\u5904\u7406\u4e86\u6240\u6709\u5fc5\u8981\u7684\u540c\u6b65\u3002\nstd::async \u4e0e std::launch::async \u53c2\u6570\u4e00\u8d77\u4f7f\u7528\uff0c\n    \u8fd9\u4f1a\u4fdd\u8bc1\u6bcf\u4e2a\u4efb\u52a1\u90fd\u5728\u4e0d\u540c\u7684\u7ebf\u7a0b\u4e0a\u5f02\u6b65\u8fd0\u884c\u3002\n\u5982\u679c\u4f60\u6ca1\u6709\u6307\u5b9a std::launch::async\uff0cC++ \u8fd0\u884c\u65f6\u53ef\u4ee5\u51b3\u5b9a\u540c\u6b65\uff08\u5ef6\u8fdf\uff09\u6267\u884c\u4efb\u52a1\uff0c\n\u8fd9\u5e76\u4e0d\u662f\u6211\u4eec\u5e0c\u671b\u770b\u5230\u7684\u3002\n    future.get() \u8c03\u7528\u5c06\u963b\u585e\u4e3b\u7ebf\u7a0b\uff0c\u76f4\u5230\u76f8\u5e94\u7684\u4efb\u52a1\u5b8c\u6210\uff0c\u5e76\u8fd4\u56de\u7ed3\u679c\u3002\n\u8fd9\u4f7f\u5f97\u6211\u4eec\u53ef\u4ee5\u5b89\u5168\u5730\u83b7\u53d6\u7ed3\u679c\uff0c\u800c\u4e0d\u4f1a\u53d1\u751f\u7ade\u4e89\u6761\u4ef6\u6216\u8005\u9700\u8981\u4f7f\u7528\u4e92\u65a5\u9501\u3002*\/<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">4. mutable keyword<\/h3>\n\n\n\n<p>First, let&#039;s review what the mutable keyword is. In addition to being used in lambda expressions, we also generally use it in class member declarations.<\/p>\n\n\n\n<p>When in a<strong>Class member variables<\/strong>When you use the mutable keyword, you can modify this member variable in the const member function of the class. This is usually used for members that do not affect the external state of the object, such as caches, debugging information, or data that can be calculated lazily.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class MyClass {\npublic:\n    mutable int cache; \/\/ \u53ef\u4ee5\u5728const\u6210\u5458\u51fd\u6570\u4e2d\u4fee\u6539\n    int data;\n\n    MyClass() : data(0), cache(0) {}\n\n    void setData(int d) const {\n        \/\/ data = d; \/\/ \u7f16\u8bd1\u9519\u8bef\uff1a\u4e0d\u80fd\u5728const\u51fd\u6570\u4e2d\u4fee\u6539\u975emutable\u6210\u5458\n        cache = d;\n    }\n};<\/code><\/pre>\n\n\n\n<p><strong>In lambda expressions<\/strong>, the mutable keyword allows you to modify the copy of the variable captured inside the Lambda. By default, the () in the Lambda expression is const, and generally you cannot modify the variable captured by value. Unless you use mutable.<\/p>\n\n\n\n<p>Here<strong>Key Points<\/strong>Mutable allows modification of the closure&#039;s own member variables<strong>Instances<\/strong>, rather than the original variables in the outer scope. This means that the closure has <strong>&quot;Closedness&quot; is still maintained<\/strong>, because it does not change the state of the outer scope, but only changes its own internal state.<\/p>\n\n\n\n<p>Invalid example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>int x = 0; auto f = [x]() { x++; \/\/ error: cannot modify captured variable}; f();<\/code><\/pre>\n\n\n\n<p>It should be like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>int x = 0; auto f = [x]() mutable { x++; std::cout &lt;&lt; x &lt;&lt; std::endl; }; f(); \/\/ Correct: outputs 1<\/code><\/pre>\n\n\n\n<p>Practical example:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Capturing variable modifications<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;vector&gt;\n\nint main() {\n    int count = 0;\n\n    \/\/ \u521b\u5efa\u4e00\u4e2a\u53ef\u53d8lambda\u8868\u8fbe\u5f0f\uff0c\u6bcf\u6b21\u8c03\u7528\u90fd\u9012\u589ecount\n    auto increment = &#91;count]() mutable {\n        count++;\n        std::cout &lt;&lt; count &lt;&lt; std::endl;\n    };\n\n    increment(); \/\/ \u8f93\u51fa 1\n    increment(); \/\/ \u8f93\u51fa 2\n    increment(); \/\/ \u8f93\u51fa 3\n\n    \/\/ \u5916\u90e8\u7684count\u4ecd\u7136\u662f0\uff0c\u56e0\u4e3a\u5b83\u662f\u901a\u8fc7\u503c\u6355\u83b7\u7684\n    std::cout &lt;&lt; \"External count: \" &lt;&lt; count &lt;&lt; std::endl; \/\/ \u8f93\u51fa External count: 0\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"2\">\n<li>Generate a unique ID<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n\nint main() {\n    int lastId = 0;\n\n    auto generateId = &#91;lastId]() mutable -&gt; int {\n        return ++lastId; \/\/ \u9012\u589e\u5e76\u8fd4\u56de\u65b0\u7684ID\n    };\n\n    std::cout &lt;&lt; \"New ID: \" &lt;&lt; generateId() &lt;&lt; std::endl; \/\/ \u8f93\u51fa New ID: 1\n    std::cout &lt;&lt; \"New ID: \" &lt;&lt; generateId() &lt;&lt; std::endl; \/\/ \u8f93\u51fa New ID: 2\n    std::cout &lt;&lt; \"New ID: \" &lt;&lt; generateId() &lt;&lt; std::endl; \/\/ \u8f93\u51fa New ID: 3\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"3\">\n<li>State retention<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;algorithm&gt;\n#include &lt;vector&gt;\n\nint main() {\n    std::vector&lt;int&gt; numbers = {1, 2, 3, 4, 5};\n\n    \/\/ \u521d\u59cb\u72b6\u6001\n    int accumulator = 0;\n\n    \/\/ \u521b\u5efa\u4e00\u4e2a\u53ef\u53d8lambda\u8868\u8fbe\u5f0f\u6765\u7d2f\u52a0\u503c\n    auto sum = &#91;accumulator](int value) mutable {\n        accumulator += value;\n        return accumulator; \/\/ \u8fd4\u56de\u5f53\u524d\u7d2f\u52a0\u503c\n    };\n\n    std::vector&lt;int&gt; runningTotals(numbers.size());\n\n    \/\/ \u5bf9\u6bcf\u4e2a\u5143\u7d20\u5e94\u7528sum\uff0c\u751f\u6210\u8fd0\u884c\u603b\u548c\n    std::transform(numbers.begin(), numbers.end(), runningTotals.begin(), sum);\n\n    \/\/ \u8f93\u51fa\u8fd0\u884c\u603b\u548c\n    for (int total : runningTotals) {\n        std::cout &lt;&lt; total &lt;&lt; \" \"; \/\/ \u8f93\u51fa 1 3 6 10 15\n    }\n    std::cout &lt;&lt; std::endl;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">5. Lambda return value deduction<\/h3>\n\n\n\n<p>When lambda expressions were introduced in C++11, the return type of the lambda usually needed to be explicitly specified.<\/p>\n\n\n\n<p>Starting from C++14, the deduction of Lambda return values has been improved and automatic type deduction has been introduced.<\/p>\n\n\n\n<p>The deduction of lambda return values in C++14 follows the following rules:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>If the lambda function body contains the return keyword, and the type of the expressions following all return statements is the same, then the lambda return type is deduced to be that type.<\/li>\n\n\n\n<li>If the body of the lambda function is a single return statement, or can be considered a single return statement (such as a constructor or brace initializer), the return type is inferred to be the type of the return statement expression.<\/li>\n\n\n\n<li>If the lambda function does not return any value (i.e. there is no return statement in the function body), or if the function body contains only return statements that do not return a value (i.e. return;), the deduced return type is void.<\/li>\n\n\n\n<li><strong>C++11 return value deduction example<\/strong><\/li>\n<\/ol>\n\n\n\n<p>In C++11, if the lambda body contains multiple return statements, the return type must be explicitly specified.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auto f = [](int x) -&gt; double { \/\/ explicitly specify the return type if (x &gt; 0) return x * 2.5; else return x \/ 2.0; };<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>C++14 automatic deduction<\/strong><\/li>\n<\/ul>\n\n\n\n<p>In C++14, the return type of the above lambda expression can be automatically deduced.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auto f = [](int x) { \/\/ The return type is automatically deduced to double if (x &gt; 0) return x * 2.5; \/\/ double else return x \/ 2.0; \/\/ double };<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Error demonstration<\/strong><\/li>\n<\/ul>\n\n\n\n<p>If the type of the return statement does not match, it cannot be automatically deduced, which will result in a compilation error.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auto g = [](int x) { \/\/ Compilation error because the return type is inconsistent if (x &gt; 0) return x * 2.5; \/\/ double else return x; \/\/ int };<\/code><\/pre>\n\n\n\n<p>But after C++17, if the return types are so different that they cannot be unified into a common type directly or through conversion, you can use std::variant or std::any, which can contain multiple different types:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;variant&gt;\n\nauto g = &#91;](int x) -&gt; std::variant&lt;int, double&gt; {\n    if (x &gt; 0)\n        return x * 2.5; \/\/ \u8fd4\u56dedouble\u7c7b\u578b\n    else\n        return x;       \/\/ \u8fd4\u56deint\u7c7b\u578b\n};<\/code><\/pre>\n\n\n\n<p>The lambda expression returns a std::variant type, that is, a superposition state of int or double type, and subsequent callers can then check this variable and handle it accordingly. This part will not be discussed in detail.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6. Nested Lambda<\/h3>\n\n\n\n<p>It can also be called nested lambda, which is an advanced functional programming technique to write a lambda inside a lambda.<\/p>\n\n\n\n<p>Here is a simple example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;vector&gt;\n#include &lt;algorithm&gt;\n\nint main() {\n    std::vector&lt;int&gt; numbers = {1, 2, 3, 4, 5};\n\n    \/\/ \u5916\u5c42Lambda\u7528\u4e8e\u904d\u5386\u96c6\u5408\n    std::for_each(numbers.begin(), numbers.end(), &#91;](int x) {\n        \/\/ \u5d4c\u5957Lambda\u7528\u4e8e\u8ba1\u7b97\u5e73\u65b9\n        auto square = &#91;](int y) { return y * y; };\n\n        \/\/ \u8c03\u7528\u5d4c\u5957Lambda\u5e76\u6253\u5370\u7ed3\u679c\n        std::cout &lt;&lt; square(x) &lt;&lt; ' ';\n    });\n\n    std::cout &lt;&lt; std::endl;\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>But we need to pay attention to many issues:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Don&#039;t make it too complicated; readability is the main consideration.<\/li>\n\n\n\n<li>Note the lifetime of variables in the capture list, which will also be discussed in detail in the following examples.<\/li>\n\n\n\n<li>Capture lists should be kept as simple as possible to avoid errors.<\/li>\n\n\n\n<li>The compiler may not optimize nested lambdas as well as top-level functions or class member functions.<\/li>\n<\/ol>\n\n\n\n<p>If a nested Lambda captures local variables of an outer Lambda, you need to pay attention to the lifecycle of the variables. If the execution of the nested Lambda continues beyond the lifecycle of the outer Lambda, the captured local variables will no longer be valid and an error will be reported.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;functional&gt;\n\nstd::function&lt;int()&gt; createLambda() {\n    int localValue = 10; \/\/ \u5916\u5c42Lambda\u7684\u5c40\u90e8\u53d8\u91cf\n\n    \/\/ \u8fd4\u56de\u4e00\u4e2a\u6355\u83b7localValue\u7684Lambda\n    return &#91;localValue]() mutable {\n        return ++localValue; \/\/ \u8bd5\u56fe\u4fee\u6539\u6355\u83b7\u7684\u53d8\u91cf\uff08\u7531\u4e8e\u662f\u503c\u6355\u83b7\uff0c\u8fd9\u662f\u5408\u6cd5\u7684\uff09\n    };\n}\n\nint main() {\n    auto myLambda = createLambda(); \/\/ myLambda\u73b0\u5728\u6301\u6709\u4e00\u4e2a\u6355\u83b7\u4e86\u5df2\u7ecf\u9500\u6bc1\u7684\u5c40\u90e8\u53d8\u91cf\u7684\u526f\u672c\n\n    std::cout &lt;&lt; myLambda() &lt;&lt; std::endl; \/\/ \u8fd9\u5c06\u8f93\u51fa11\uff0c\u4f46\u662f\u4f9d\u8d56\u4e8e\u5df2\u7ecf\u9500\u6bc1\u7684localValue\u7684\u526f\u672c\n    std::cout &lt;&lt; myLambda() &lt;&lt; std::endl; \/\/ \u518d\u6b21\u8c03\u7528\u5c06\u8f93\u51fa12\uff0c\u7ee7\u7eed\u4f9d\u8d56\u4e8e\u90a3\u4e2a\u526f\u672c\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>To explain, since Lambda captures localValue by value, it holds a copy of localValue, and the life cycle of this copy is the same as that of the returned Lambda object.<\/p>\n\n\n\n<p>When we call myLambda() in the main function, it operates on the state of the localValue copy, not the original localValue (which has been destroyed after the createLambda function is executed). Although undefined behavior is not triggered here, the situation will be different if we use reference capture:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>std::function&lt;int()&gt; createLambda() {\n    int localValue = 10; \/\/ \u5916\u5c42Lambda\u7684\u5c40\u90e8\u53d8\u91cf\n\n    \/\/ \u8fd4\u56de\u4e00\u4e2a\u6355\u83b7localValue\u5f15\u7528\u7684Lambda\n    return &#91;&amp;localValue]() mutable {\n        return ++localValue; \/\/ \u8bd5\u56fe\u4fee\u6539\u6355\u83b7\u7684\u53d8\u91cf\n    };\n}\n\/\/ \u6b64\u65f6\u4f7f\u7528createLambda\u8fd4\u56de\u7684Lambda\u5c06\u4f1a\u5bfc\u81f4\u672a\u5b9a\u4e49\u884c\u4e3a<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">7. Lambda, std:function and delegates<\/h3>\n\n\n\n<p>Lambda expression, std::function and delegate are three different concepts used to implement function call and callback mechanism in C++. Next, we will explain them one by one.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Lambda<\/strong><\/li>\n<\/ul>\n\n\n\n<p>C++11 introduces a syntax for defining anonymous function objects. Lambda is used to create a callable entity, namely a Lambda closure, which is usually passed to an algorithm or used as a callback function. Lambda expressions can capture variables in scope, either by value (copy) or by reference. Lambda expressions are defined inside functions, their types are unique, and cannot be explicitly specified.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auto lambda = [](int a, int b) { return a + b; }; auto result = lambda(2, 3); \/\/ Calling Lambda Expression<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>std::function<\/li>\n<\/ul>\n\n\n\n<p>std::function is a type-erased wrapper introduced in C++11 that can<strong>storage<\/strong>,<strong>Call<\/strong>and<strong>copy<\/strong>Any callable entity, such as function pointers, member function pointers, lambda expressions, and function objects. The cost is that the overhead is large.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>std::function func = lambda; auto result = func(2, 3); \/\/ Call the Lambda expression using the std::function object<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Delegation<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Delegate is not a formal term in C++. Delegate is usually a mechanism to delegate function calls to other objects. In C#, a delegate is a type-safe function pointer. In C++, there are generally several ways to implement delegates: function pointer, member function pointer, std::function and function object. The following is an example of a delegate constructor.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class MyClass {\npublic:\n    MyClass(int value) : MyClass(value, \"default\") { \/\/ \u59d4\u6258\u7ed9\u53e6\u4e00\u4e2a\u6784\u9020\u51fd\u6570\n        std::cout &lt;&lt; \"Constructor with single parameter called.\" &lt;&lt; std::endl;\n    }\n\n    MyClass(int value, std::string text) {\n        std::cout &lt;&lt; \"Constructor with two parameters called: \" &lt;&lt; value &lt;&lt; \", \" &lt;&lt; text &lt;&lt; std::endl;\n    }\n};\n\nint main() {\n    MyClass obj(30); \/\/ \u8fd9\u5c06\u8c03\u7528\u4e24\u4e2a\u6784\u9020\u51fd\u6570\n}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Comparison of the three<\/strong><\/li>\n<\/ul>\n\n\n\n<p><strong>Lambda Expressions<\/strong>It is lightweight and well suited for defining simple local callbacks and as parameters to algorithms.<\/p>\n\n\n\n<p>std::function is heavier, but more flexible. For example, if you have a scenario where you need to store different types of callback functions, std::function is an ideal choice because it can store any type of callable entity. An example that demonstrates its flexibility.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;functional&gt;\n#include &lt;vector&gt;\n\n\/\/ \u4e00\u4e2a\u63a5\u6536int\u5e76\u8fd4\u56devoid\u7684\u51fd\u6570\nvoid printNumber(int number) {\n    std::cout &lt;&lt; \"Number: \" &lt;&lt; number &lt;&lt; std::endl;\n}\n\n\/\/ \u4e00\u4e2aLambda\u8868\u8fbe\u5f0f\nauto printSum = &#91;](int a, int b) {\n    std::cout &lt;&lt; \"Sum: \" &lt;&lt; (a + b) &lt;&lt; std::endl;\n};\n\n\/\/ \u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\nclass PrintMessage {\npublic:\n    void operator()(const std::string &amp;message) const {\n        std::cout &lt;&lt; \"Message: \" &lt;&lt; message &lt;&lt; std::endl;\n    }\n};\n\nint main() {\n    \/\/ \u521b\u5efa\u4e00\u4e2astd::function\u7684\u5411\u91cf\uff0c\u53ef\u4ee5\u5b58\u50a8\u4efb\u4f55\u7c7b\u578b\u7684\u53ef\u8c03\u7528\u5bf9\u8c61\n    std::vector&lt;std::function&lt;void()&gt;&gt; callbacks;\n\n    \/\/ \u6dfb\u52a0\u4e00\u4e2a\u666e\u901a\u51fd\u6570\u7684\u56de\u8c03\n    int number_to_print = 42;\n    callbacks.push_back(&#91;=]{ printNumber(number_to_print); });\n\n    \/\/ \u6dfb\u52a0\u4e00\u4e2aLambda\u8868\u8fbe\u5f0f\u7684\u56de\u8c03\n    int a = 10, b = 20;\n    callbacks.push_back(&#91;=]{ printSum(a, b); });\n\n    \/\/ \u6dfb\u52a0\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u7684\u56de\u8c03\n    std::string message = \"Hello World\";\n    PrintMessage printMessage;\n    callbacks.push_back(&#91;=]{ printMessage(message); });\n\n    \/\/ \u6267\u884c\u6240\u6709\u7684\u56de\u8c03\n    for (auto&amp; callback : callbacks) {\n        callback();\n    }\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p><strong>Delegation<\/strong>Usually related to event handling. There is no built-in event handling mechanism in C++, so std::function and Lambda expressions are often used to implement the delegation pattern. Specifically, you define a callback interface, and users can register their own functions or Lambda expressions to this interface so that they can be called when an event occurs. The general steps are as follows (by the way, an example):<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Defines the types that can be called<\/strong>: You need to determine what parameters your callback function or Lambda expression needs to accept and what type of result it returns.<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>using Callback = std::function ; \/\/ callback with no parameters and return value<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"2\">\n<li><strong>Create a class to manage callbacks<\/strong>: This class will hold all callback functions and allow users to add or remove callbacks.<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>class Button {\nprivate:\n    std::vector&lt;Callback&gt; onClickCallbacks; \/\/ \u5b58\u50a8\u56de\u8c03\u7684\u5bb9\u5668\n\npublic:\n    void addClickListener(const Callback&amp; callback) {\n        onClickCallbacks.push_back(callback);\n    }\n\n    void click() {\n        for (auto&amp; callback : onClickCallbacks) {\n            callback(); \/\/ \u6267\u884c\u6bcf\u4e00\u4e2a\u56de\u8c03\n        }\n    }\n};<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"3\">\n<li><strong>Provide a method to add a callback<\/strong>: This method allows users to add their own functions or Lambda expressions<strong>Register as callback<\/strong>.<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>Button button; button.addClickListener([]() { std::cout &lt;&lt; &quot;Button was clicked!&quot; &lt;&lt; std::endl; });<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"4\">\n<li><strong>Provide a method to execute the callback<\/strong>\uff1aWhen necessary, this method will<strong>Call all registered callback functions<\/strong>.<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>button.click(); \/\/ User clicks the button to trigger all callbacks<\/code><\/pre>\n\n\n\n<p>Isn\u2019t it very simple? Let\u2019s take another example to deepen our understanding.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;functional&gt;\n#include &lt;iostream&gt;\n#include &lt;vector&gt;\n\nclass Delegate {\npublic:\n    using Callback = std::function&lt;void(int)&gt;;  \/\/ \u5b9a\u4e49\u56de\u8c03\u7c7b\u578b\uff0c\u8fd9\u91cc\u7684\u56de\u8c03\u63a5\u6536\u4e00\u4e2aint\u53c2\u6570\n\n    \/\/ \u6ce8\u518c\u56de\u8c03\u51fd\u6570\n    void registerCallback(const Callback&amp; callback) {\n        callbacks.push_back(callback);\n    }\n\n    \/\/ \u89e6\u53d1\u6240\u6709\u56de\u8c03\u51fd\u6570\n    void notify(int value) {\n        for (const auto&amp; callback : callbacks) {\n            callback(value);  \/\/ \u6267\u884c\u56de\u8c03\n        }\n    }\n\nprivate:\n    std::vector&lt;Callback&gt; callbacks;  \/\/ \u5b58\u50a8\u56de\u8c03\u7684\u5bb9\u5668\n};\n\nint main() {\n    Delegate del;\n\n    \/\/ \u7528\u6237\u6ce8\u518c\u81ea\u5df1\u7684\u51fd\u6570\n    del.registerCallback(&#91;](int n) {\n        std::cout &lt;&lt; \"Lambda 1: \" &lt;&lt; n &lt;&lt; std::endl;\n    });\n\n    \/\/ \u53e6\u4e00\u4e2aLambda\u8868\u8fbe\u5f0f\n    del.registerCallback(&#91;](int n) {\n        std::cout &lt;&lt; \"Lambda 2: \" &lt;&lt; n * n &lt;&lt; std::endl;\n    });\n\n    \/\/ \u89e6\u53d1\u56de\u8c03\n    del.notify(10);  \/\/ \u8fd9\u5c06\u8c03\u7528\u6240\u6709\u6ce8\u518c\u7684Lambda\u8868\u8fbe\u5f0f\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">8. Lambda in asynchronous and concurrent programming<\/h3>\n\n\n\n<p>All because Lambda has the function of capturing and storing state, which makes it very useful when we write modern C++ concurrent programming.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Lambda and Threads<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Use lambda expressions directly in the std::thread constructor to define the code that the thread should execute.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;thread&gt;\n#include &lt;iostream&gt;\n\nint main() {\n    int value = 42;\n\n    \/\/ \u521b\u5efa\u4e00\u4e2a\u65b0\u7ebf\u7a0b\uff0c\u4f7f\u7528 Lambda \u8868\u8fbe\u5f0f\u4f5c\u4e3a\u7ebf\u7a0b\u51fd\u6570\n    std::thread worker(&#91;value]() {\n        std::cout &lt;&lt; \"Value in thread: \" &lt;&lt; value &lt;&lt; std::endl;\n    });\n\n    \/\/ \u4e3b\u7ebf\u7a0b\u7ee7\u7eed\u6267\u884c...\n\n    \/\/ \u7b49\u5f85\u5de5\u4f5c\u7ebf\u7a0b\u5b8c\u6210\n    worker.join();\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Lambda and<\/strong> <strong>std::async<\/strong><\/li>\n<\/ul>\n\n\n\n<p>std::async is a tool that allows you to easily create asynchronous functions. After the calculation is completed, it returns a std::future object. You can call get, but it will block if the execution is not completed. There are many interesting things about async, which I will not go into here.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;future&gt;\n#include &lt;iostream&gt;\n\nint main() {\n    \/\/ \u542f\u52a8\u4e00\u4e2a\u5f02\u6b65\u4efb\u52a1\n    auto future = std::async(&#91;]() {\n        \/\/ \u6267\u884c\u4e00\u4e9b\u64cd\u4f5c...\n        return \"Result from async task\";\n    });\n\n    \/\/ \u5728\u6b64\u671f\u95f4\uff0c\u4e3b\u7ebf\u7a0b\u53ef\u4ee5\u6267\u884c\u5176\u4ed6\u4efb\u52a1...\n\n    \/\/ \u83b7\u53d6\u5f02\u6b65\u64cd\u4f5c\u7684\u7ed3\u679c\n    std::string result = future.get();\n    std::cout &lt;&lt; result &lt;&lt; std::endl;\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Lambda and<\/strong> <strong>std::funtion<\/strong><\/li>\n<\/ul>\n\n\n\n<p>These two are often used together, so let&#039;s take an example of storing a callable callback.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;functional&gt;\n#include &lt;vector&gt;\n#include &lt;iostream&gt;\n#include &lt;thread&gt;\n\n\/\/ \u4e00\u4e2a\u5b58\u50a8 std::function \u5bf9\u8c61\u7684\u4efb\u52a1\u961f\u5217\nstd::vector&lt;std::function&lt;void()&gt;&gt; tasks;\n\n\/\/ \u6dfb\u52a0\u4efb\u52a1\u7684\u51fd\u6570\nvoid addTask(const std::function&lt;void()&gt;&amp; task) {\n    tasks.push_back(task);\n}\n\nint main() {\n    \/\/ \u6dfb\u52a0\u4e00\u4e2a Lambda \u8868\u8fbe\u5f0f\u4f5c\u4e3a\u4efb\u52a1\n    addTask(&#91;]() {\n        std::cout &lt;&lt; \"Task 1 executed\" &lt;&lt; std::endl;\n    });\n\n    \/\/ \u542f\u52a8\u4e00\u4e2a\u65b0\u7ebf\u7a0b\u6765\u5904\u7406\u4efb\u52a1\n    std::thread worker(&#91;]() {\n        for (auto&amp; task : tasks) {\n            task(); \/\/ \u6267\u884c\u4efb\u52a1\n        }\n    });\n\n    \/\/ \u4e3b\u7ebf\u7a0b\u7ee7\u7eed\u6267\u884c...\n    worker.join();\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">9. Generic Lambda (C++14)<\/h3>\n\n\n\n<p>Use the auto keyword to perform type inference in the argument list.<\/p>\n\n\n\n<p><strong>Generic basic syntax:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auto lambda = [](auto x, auto y) { return x + y; };<\/code><\/pre>\n\n\n\n<p>Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;numeric&gt;\n\nint main() {\n    std::vector&lt;int&gt; vi = {1, 2, 3, 4};\n    std::vector&lt;double&gt; vd = {1.1, 2.2, 3.3, 4.4, 5.5};\n\n    \/\/ \u4f7f\u7528\u6cdb\u578b Lambda \u6253\u5370 int \u7c7b\u578b\u7684\u5143\u7d20\n    std::for_each(vi.begin(), vi.end(), &#91;](auto n) {\n        std::cout &lt;&lt; n &lt;&lt; ' ';\n    });\n    std::cout &lt;&lt; '\\n';\n\n    \/\/ \u4f7f\u7528\u6cdb\u578b Lambda \u6253\u5370 double \u7c7b\u578b\u7684\u5143\u7d20\n    std::for_each(vd.begin(), vd.end(), &#91;](auto n) {\n        std::cout &lt;&lt; n &lt;&lt; ' ';\n    });\n    std::cout &lt;&lt; '\\n';\n\n    \/\/ \u4f7f\u7528\u6cdb\u578b Lambda \u8ba1\u7b97 int \u7c7b\u578b\u7684\u5411\u91cf\u7684\u548c\n    auto sum_vi = std::accumulate(vi.begin(), vi.end(), 0, &#91;](auto total, auto n) {\n        return total + n;\n    });\n    std::cout &lt;&lt; \"Sum of vi: \" &lt;&lt; sum_vi &lt;&lt; '\\n';\n\n    \/\/ \u4f7f\u7528\u6cdb\u578b Lambda \u8ba1\u7b97 double \u7c7b\u578b\u7684\u5411\u91cf\u7684\u548c\n    auto sum_vd = std::accumulate(vd.begin(), vd.end(), 0.0, &#91;](auto total, auto n) {\n        return total + n;\n    });\n    std::cout &lt;&lt; \"Sum of vd: \" &lt;&lt; sum_vd &lt;&lt; '\\n';\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>It is also possible to make a lambda that prints any type of container.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;list&gt;\n\nint main() {\n    std::vector&lt;int&gt; vec{1, 2, 3, 4};\n    std::list&lt;double&gt; lst{1.1, 2.2, 3.3, 4.4};\n\n    auto print = &#91;](const auto&amp; container) {\n        for (const auto&amp; val : container) {\n            std::cout &lt;&lt; val &lt;&lt; ' ';\n        }\n        std::cout &lt;&lt; '\\n';\n    };\n\n    print(vec); \/\/ \u6253\u5370 vector&lt;int&gt;\n    print(lst); \/\/ \u6253\u5370 list&lt;double&gt;\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">10. Lambda Scope<\/h3>\n\n\n\n<p>First, Lambda can capture local variables within the scope in which it is defined. After capture, even if the original scope ends, copies or references of these variables (depending on the capture method) can still continue to be used.<\/p>\n\n\n\n<p>It is important to note that if a variable is captured by reference and the original scope of the variable has been destroyed, this will lead to undefined behavior.<\/p>\n\n\n\n<p>Lambda can also capture global variables, but this is not achieved through a capture list, because global variables can be accessed from anywhere.<\/p>\n\n\n\n<p>If you have a lambda nested inside another lambda, the inner lambda can capture variables in the capture list of the outer lambda.<\/p>\n\n\n\n<p>When Lambda captures a value, even if the original value is gone and Lambda is gone (returned to somewhere else), all variables captured by the value will be copied to the Lambda object. The life cycle of these variables will automatically continue until the Lambda object itself is destroyed. Here is an example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;functional&gt;\n\nstd::function&lt;void()&gt; createLambda() {\n    int localValue = 100;  \/\/ \u5c40\u90e8\u53d8\u91cf\n    return &#91;=]() mutable {  \/\/ \u4ee5\u503c\u6355\u83b7\u7684\u65b9\u5f0f\u590d\u5236localValue\n        std::cout &lt;&lt; localValue++ &lt;&lt; '\\n';\n    };\n}\n\nint main() {\n    auto myLambda = createLambda();  \/\/ Lambda\u590d\u5236\u4e86localValue\n    myLambda();  \/\/ \u5373\u4f7fcreateLambda\u7684\u4f5c\u7528\u57df\u5df2\u7ecf\u7ed3\u675f\uff0c\u590d\u5236\u7684localValue\u4ecd\u7136\u5b58\u5728\u4e8emyLambda\u4e2d\n    myLambda();  \/\/ \u53ef\u4ee5\u5b89\u5168\u5730\u7ee7\u7eed\u8bbf\u95ee\u548c\u4fee\u6539\u8be5\u526f\u672c\n}<\/code><\/pre>\n\n\n\n<p>When lambda captures a reference, it\u2019s another story. Smart readers should be able to guess that if the scope of the original variable ends, the lambda depends on a dangling reference, which will lead to undefined behavior.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">11. Practice \u2013 Function Compute Library<\/h3>\n\n\n\n<p>After all this talk, it&#039;s time to put it into practice. No matter what you do, the following are the knowledge points you need to master:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>capture<\/li>\n\n\n\n<li>Higher-order functions<\/li>\n\n\n\n<li>Callable Objects<\/li>\n\n\n\n<li>Lambda Storage<\/li>\n\n\n\n<li>Mutable Lambdas<\/li>\n\n\n\n<li>Generic Lambda<\/li>\n<\/ul>\n\n\n\n<p><strong>Our goal in this section is to create a math library that supports vector operations, matrix operations, and provides a function parser that accepts a mathematical expression in string form and returns a computable Lambda. Let&#039;s get started right away.<\/strong><\/p>\n\n\n\n<p>This project starts with simple mathematical function calculations and gradually expands to complex mathematical expression parsing and calculations. Project writing steps:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Basic vector and matrix operations<\/strong><\/li>\n\n\n\n<li><strong>Function parser<\/strong><\/li>\n\n\n\n<li><strong>More advanced math functions<\/strong><\/li>\n\n\n\n<li><strong>Composite Functions<\/strong><\/li>\n\n\n\n<li><strong>Advanced Mathematical Operations<\/strong><\/li>\n\n\n\n<li><strong>More expansion...<\/strong><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Basic vector and matrix operations<\/h3>\n\n\n\n<p>First, define the data structure of vectors and matrices and implement basic arithmetic operations (addition and subtraction).<\/p>\n\n\n\n<p>In order to simplify the project and focus on the use of Lambda, I did not use templates, so all data is implemented with std::vector.<\/p>\n\n\n\n<p>In the following code, I have implemented a basic vector framework. Please improve the framework by yourself, including vector subtraction, dot multiplication and other operations.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Vector.h\n#include &lt;vector&gt;\n#include &lt;ostream&gt;\n\nclass Vector {\nprivate:\n    std::vector&lt;double&gt; elements;\npublic:\n    \/\/ \u6784\u9020\u51fd\u6570 - explicit\u9632\u6b62\u9690\u5f0f\u8f6c\u6362\n    Vector() = default;\n    explicit Vector(const std::vector&lt;double&gt; &amp;elems);\n\n    Vector operator+const Vector&amp; rhs) const;\n\n    \/\/ \u83b7\u53d6\u5411\u91cf\u5927\u5c0f\n    &#91;&#91;nodiscard]] size_t size() const { return elements.size(); }\n\n    \/\/ \u8bbf\u95ee\u5143\u7d20\uff0c\u8fd4\u56de\u5bf9\u8c61\u7684\u5f15\u7528 double&amp;\u3002\u5982\u679cVector\u5bf9\u8c61\u662f\u5e38\u91cf\uff0c\u5c31\u4f7f\u7528\u4e0b\u9762\u7684\u7248\u672c\n    double&amp; operator&#91;](size_t index) { return elements&#91;index]; }\n    const double&amp; operator&#91;](size_t index) const { return elements&#91;index]; }\n\n    \/\/ \u8fed\u4ee3\u5668\u652f\u6301\n    auto begin() { return elements.begin(); }\n    auto end() { return elements.end(); }\n    auto begin() const { return elements.cbegin(); }\n    auto end() const { return elements.cend(); }\n\n    \/\/ \u8ba9\u91cd\u8f7d\u7684\u6d41\u8f93\u51fa\u8fd0\u7b97\u7b26\u6210\u4e3a\u53cb\u5143\u51fd\u6570\uff0c\u4ee5\u4fbf\u5b83\u53ef\u4ee5\u8bbf\u95ee\u79c1\u6709\u6210\u5458\n    friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, const Vector&amp; v);\n};\n\/\/\/ Vector.cpp\n#include \"Vector.h\"\nVector::Vector(const std::vector&lt;double&gt;&amp; elems) : elements(elems){}\n\nVector Vector::operator+(const Vector &amp;rhs) const {\n    \/\/ \u9996\u5148\u786e\u4fdd\u4e24\u4e2a\u5411\u91cf\u4e00\u81f4\n    if( this-&gt;size() != rhs.size() )\n        throw std::length_error(\"\u5411\u91cf\u5927\u5c0f\u4e0d\u4e00\u81f4\uff01\");\n    Vector result;\n    result.elements.reserve(this-&gt;size()); \/\/ \u63d0\u524d\u5206\u914d\u5185\u5b58\n    \/\/ \u4f7f\u7528\u8fed\u4ee3\u5668\u904d\u5386\u5411\u91cf\u5404\u4e2a\u5143\u7d20\n    std::transform(this-&gt;begin(), this-&gt;end(), rhs.begin(), std::back_inserter(result.elements),\n                   &#91;](double_t a,double_t b){ return a+b; });\n    return result;\n}\n\nstd::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, const Vector&amp; v) {\n    os &lt;&lt; '&#91;';\n    for (size_t i = 0; i &lt; v.elements.size(); ++i) {\n        os &lt;&lt; v.elements&#91;i];\n        if (i &lt; v.elements.size() - 1) {\n            os &lt;&lt; \", \";\n        }\n    }\n    os &lt;&lt; ']';\n    return os;\n}<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>You can use the [[nodiscard]] tag in the declaration operation to remind the compiler to check whether the return value is used, and then users of the library will be reminded in the editor, such as the following.<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">Function parser<\/h3>\n\n\n\n<p>Design a function parser that can convert mathematical expressions in string form into Lambda expressions.<\/p>\n\n\n\n<p>Creating a function parser that can parse mathematical expressions in string form and convert them into Lambda expressions involves parsing theory. To simplify the example, we currently only parse the most basic + and -. Then package the function parser into an ExpressionParser tool class.<\/p>\n\n\n\n<p>First we create a parser that recognizes + and \u2013 signs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ ExpressionParser.h\n#include &lt;functional&gt;\n#include &lt;string&gt;\n\nusing ExprFunction = std::function&lt;double(double, double)&gt;;\n\nclass ExpressionParser {\npublic:\n    static ExprFunction parse_simple_expr(const std::string&amp; expr);\n};\n\/\/ ExpressionParser.cpp\n#include \"ExpressionParser.h\"\n\nExprFunction ExpressionParser::parse_simple_expr\n        (const std::string &amp;expr)\n{\n    if (expr.find('+') != std::string::npos) {\n        return &#91;](double x, double y) { return x + y; };\n    }\n    else if (expr.find('-') != std::string::npos) {\n        return &#91;](double x, double y) { return x - y; };\n    }\n    \/\/ \u66f4\u591a\u64cd\u4f5c...\n    return nullptr;\n}<\/code><\/pre>\n\n\n\n<p>This section is not very relevant to Lambda, so you can skip it. Then we can improve the function parser to recognize numbers based on this. Split the string into tokens (numbers and operators), and then perform operations based on the operators. For more complex expressions, you need to use algorithms such as RPN or existing parsing libraries, so I won&#039;t make it so complicated here.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ ExpressionParser.h\n...\n#include &lt;sstream&gt;\n...\nstatic double parse_and_compute(const std::string&amp; expr);\n...\n\/\/ ExpressionParser.cpp\n...\ndouble ExpressionParser::parse_and_compute(const std::string&amp; expr) {\n    std::istringstream iss(expr);\n    std::vector&lt;std::string&gt; tokens;\n    std::string token;\n    while (iss &gt;&gt; token) {\n        tokens.push_back(token);\n    }\n\n    if (tokens.size() != 3) {\n        throw std::runtime_error(\"Invalid expression format.\");\n    }\n\n    double num1 = std::stod(tokens&#91;0]);\n    const std::string&amp; op = tokens&#91;1];\n    double num2 = std::stod(tokens&#91;2]);\n\n    if (op == \"+\") {\n        return num1 + num2;\n    } else if (op == \"-\") {\n        return num1 - num2;\n    } else {\n        throw std::runtime_error(\"Unsupported operator.\");\n    }\n}<\/code><\/pre>\n\n\n\n<p>test:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ main.cpp #include &quot;ExpressionParser.h&quot; ... std::string expr = &quot;10 - 25&quot;; std::cout &lt;&lt; expr &lt;&lt; &quot; = &quot; &lt;&lt; ExpressionParser::parse_and_compute(expr) &lt;&lt; std ::endl;<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Interested readers can also try to parse multiple operators using an operator precedence parsing algorithm (such as the Shunting Yard algorithm) to convert infix expressions to Reverse Polish Notation (RPN). <del>exhibit<\/del> A little bit of nonsense about data structures, which has little to do with Lambda.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;stack&gt;\n#include &lt;vector&gt;\n#include &lt;sstream&gt;\n#include &lt;map&gt;\n#include &lt;cctype&gt;\n\n\/\/ \u786e\u5b9a\u662f\u5426\u4e3a\u64cd\u4f5c\u7b26\nbool is_operator(const std::string&amp; token) {\n    return token == \"+\" || token == \"-\" || token == \"*\" || token == \"\/\";\n}\n\n\/\/ \u786e\u5b9a\u64cd\u4f5c\u7b26\u4f18\u5148\u7ea7\nint precedence(const std::string&amp; token) {\n    if (token == \"+\" || token == \"-\") return 1;\n    if (token == \"*\" || token == \"\/\") return 2;\n    return 0;\n}\n\n\/\/ \u5c06\u4e2d\u7f00\u8868\u8fbe\u5f0f\u8f6c\u6362\u4e3a\u9006\u6ce2\u5170\u8868\u793a\u6cd5\nstd::vector&lt;std::string&gt; infix_to_rpn(const std::vector&lt;std::string&gt;&amp; tokens) {\n    std::vector&lt;std::string&gt; output;\n    std::stack&lt;std::string&gt; operators;\n\n    for (const auto&amp; token : tokens) {\n        if (is_operator(token)) {\n            while (!operators.empty() &amp;&amp; precedence(operators.top()) &gt;= precedence(token)) {\n                output.push_back(operators.top());\n                operators.pop();\n            }\n            operators.push(token);\n        } else if (token == \"(\") {\n            operators.push(token);\n        } else if (token == \")\") {\n            while (!operators.empty() &amp;&amp; operators.top() != \"(\") {\n                output.push_back(operators.top());\n                operators.pop();\n            }\n            if (!operators.empty()) operators.pop();\n        } else {\n            output.push_back(token);\n        }\n    }\n\n    while (!operators.empty()) {\n        output.push_back(operators.top());\n        operators.pop();\n    }\n\n    return output;\n}\n\n\/\/ \u8ba1\u7b97\u9006\u6ce2\u5170\u8868\u793a\u6cd5\ndouble compute_rpn(const std::vector&lt;std::string&gt;&amp; tokens) {\n    std::stack&lt;double&gt; operands;\n\n    for (const auto&amp; token : tokens) {\n        if (is_operator(token)) {\n            double rhs = operands.top(); operands.pop();\n            double lhs = operands.top(); operands.pop();\n            if (token == \"+\") operands.push(lhs + rhs);\n            else if (token == \"-\") operands.push(lhs - rhs);\n            else if (token == \"*\") operands.push(lhs * rhs);\n            else operands.push(lhs \/ rhs);\n        } else {\n            operands.push(std::stod(token));\n        }\n    }\n\n    return operands.top();\n}\n\n\/\/ \u4e3b\u51fd\u6570\nint main() {\n    std::string input = \"3 + 4 * 2 \/ ( 1 - 5 )\";\n    std::istringstream iss(input);\n    std::vector&lt;std::string&gt; tokens;\n    std::string token;\n    while (iss &gt;&gt; token) {\n        tokens.push_back(token);\n    }\n\n    auto rpn = infix_to_rpn(tokens);\n    for (const auto&amp; t : rpn) {\n        std::cout &lt;&lt; t &lt;&lt; \" \";\n    }\n    std::cout &lt;&lt; std::endl;\n\n    double result = compute_rpn(rpn);\n    std::cout &lt;&lt; \"Result: \" &lt;&lt; result &lt;&lt; std::endl;\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">More advanced math functions<\/h3>\n\n\n\n<p><strong>Assumptions<\/strong>Our parser is already able to recognize more advanced mathematical operations, such as trigonometric functions, logarithms, exponentials, etc. We need to provide a Lambda expression for the corresponding operation.<\/p>\n\n\n\n<p>First we modify the aliases of two std::function with different signatures.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ ExpressionParser.cpp\nusing UnaryFunction = std::function&lt;double(double)&gt;;\nusing BinaryFunction = std::function&lt;double(double, double)&gt;;\n\n...\n\n\/\/ ExpressionParser.cpp\nUnaryFunction ExpressionParser::parse_complex_expr\n        (const std::string&amp; expr)\n{\n    using _t = std::unordered_map&lt;std::string, UnaryFunction&gt;;\n    static const _t functions = {\n            {\"sin\", &#91;](double x) -&gt; double { return std::sin(x); }},\n            {\"cos\", &#91;](double x) -&gt; double { return std::cos(x); }},\n            {\"log\", &#91;](double x) -&gt; double { return std::log(x); }},\n            \/\/ ... \u6dfb\u52a0\u66f4\u591a\u51fd\u6570\n    };\n    auto it = functions.find(expr);\n    if (it != functions.end()) {\n        return it-&gt;second;\n    } else {\n        \/\/ \u5904\u7406\u9519\u8bef\u6216\u8fd4\u56de\u4e00\u4e2a\u9ed8\u8ba4\u7684\u51fd\u6570\n        return &#91;](double) -&gt; double { return 0.0; }; \/\/ \u793a\u4f8b\u9519\u8bef\u5904\u7406\n    }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Composite Functions<\/h3>\n\n\n\n<p>To implement compound mathematical functions, you can combine multiple Lambda expressions. Here is a small example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;cmath&gt;\n#include &lt;functional&gt;\n\nint main() {\n    \/\/ \u5b9a\u4e49\u7b2c\u4e00\u4e2a\u51fd\u6570 f(x) = sin(x)\n    auto f = &#91;](double x) {\n        return std::sin(x);\n    };\n\n    \/\/ \u5b9a\u4e49\u7b2c\u4e8c\u4e2a\u51fd\u6570 g(x) = cos(x)\n    auto g = &#91;](double x) {\n        return std::cos(x);\n    };\n\n    \/\/ \u521b\u5efa\u590d\u5408\u51fd\u6570 h(x) = g(f(x)) = cos(sin(x))\n    auto h = &#91;f, g](double x) {\n        return g(f(x));\n    };\n\n    \/\/ \u4f7f\u7528\u590d\u5408\u51fd\u6570\n    double value = M_PI \/ 4;  \/\/ PI\/4\n    std::cout &lt;&lt; \"h(pi\/4) = cos(sin(pi\/4)) = \" &lt;&lt; h(value) &lt;&lt; std::endl;\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>If you want a more complicated composite function, say $\\text{cos}(\\text{sin}(\\text{exp}(x))$ , you can do this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auto exp_func = &#91;](double x) {\n    return std::exp(x);\n};\n\n\/\/ \u521b\u5efa\u590d\u5408\u51fd\u6570 h(x) = cos(sin(exp(x)))\nauto h_complex = &#91;f, g, exp_func](double x) {\n    return g(f(exp_func(x)));\n};\n\nstd::cout &lt;&lt; \"h_complex(1) = cos(sin(exp(1))) = \" &lt;&lt; h_complex(1) &lt;&lt; std::endl;<\/code><\/pre>\n\n\n\n<p>One of the advantages of using lambda expressions for function composition is that they allow you to easily create higher-order functions, that is, composite functions that are built on top of each other.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auto compose = &#91;](auto f, auto g) {\n    return &#91;f, g](double x) {\n        return g(f(x));\n    };\n};\n\nauto h_composed = compose(f, g);\nstd::cout &lt;&lt; \"h_composed(pi\/4) = \" &lt;&lt; h_composed(M_PI \/ 4) &lt;&lt; std::endl;<\/code><\/pre>\n\n\n\n<p>The above example is the core idea of higher-order functions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Advanced Mathematical Operations<\/h3>\n\n\n\n<p>Implements differential and integral calculators that can use lambda expressions to approximate the derivatives and integrals of mathematical functions.<\/p>\n\n\n\n<p>The differentiation here uses the forward difference method of numerical differentiation to approximate the reciprocal $f&#039;(x)$.<\/p>\n\n\n\n<p>The integration was performed using the numerical integration method using the trapezoidal rule.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u5fae\u5206\nauto derivative = &#91;](auto func, double h = 1e-5) {\n    return &#91;func, h](double x) {\n        return (func(x + h) - func(x)) \/ h;\n    };\n};\n\/\/ \u4f8b\u5982\uff0c\u5bf9 sin(x) \u7684\u5fae\u5206\nauto sin_derivative = derivative(&#91;](double x) { return std::sin(x); });\nstd::cout &lt;&lt; \"sin'(pi\/4) \u2248 \" &lt;&lt; sin_derivative(M_PI \/ 4) &lt;&lt; std::endl;\n\n\n\/\/ \u79ef\u5206 - \u79ef\u5206\u4e0b\u9650 a\uff0c\u79ef\u5206\u4e0a\u9650 b \u548c\u5206\u5272\u6570\u91cf n \nauto trapezoidal_integral = &#91;](auto func, double a, double b, int n = 1000) {\n    double h = (b - a) \/ n;\n    double sum = 0.5 * (func(a) + func(b));\n    for (int i = 1; i &lt; n; i++) {\n        sum += func(a + i * h);\n    }\n    return sum * h;\n};\n\/\/ \u4f8b\u5982\uff0c\u5bf9 sin(x) \u5728 0 \u5230 pi\/2 \u4e0a\u7684\u79ef\u5206\nauto integral_sin = trapezoidal_integral(&#91;](double x) { return std::sin(x); }, 0, M_PI \/ 2);\nstd::cout &lt;&lt; \"\u222bsin(x)dx from 0 to pi\/2 \u2248 \" &lt;&lt; integral_sin &lt;&lt; std::endl;<\/code><\/pre>\n\n\n\n<p><strong>Numerical Differentiation \u2013 Forward Difference Method<\/strong><\/p>\n\n\n\n<p>The numerical approximation of the derivative of the function $$f(x)$$ at the point $$x$$ can be given by the forward difference formula:<\/p>\n\n\n\n<p>Here $$h$$ represents a small increase in the value of $$x$$. When $$h$$ approaches 0, the ratio approaches the true value of the derivative. In the code, we set a relatively small value $$10^{-5}$$.<\/p>\n\n\n\n<p><strong>Numerical Integration \u2013 Trapezoidal Rule<\/strong><\/p>\n\n\n\n<p>The numerical approximation of the definite integral $$\\int_a^bf(x) d x$$ can be calculated using the trapezoidal rule:<\/p>\n\n\n\n<p>Where $$n$$ is the number of small intervals into which the interval $$[a, b]$$ is divided, and $$h$$ is the width of each small interval, which is calculated as:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Intermediate<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Lambda&#039;s underlying implementation<\/h3>\n\n\n\n<p>On the surface, lambda expressions seem to be just syntactic sugar, but in fact, the compiler will perform some underlying transformations on each lambda expression.<\/p>\n\n\n\n<p>First, the type of each lambda expression is unique. The compiler generates a unique class type for each lambda, which is often called<strong>Closure Types<\/strong>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>The concept of closure comes from closure in mathematics. It refers to a structure whose internal operations are closed and do not depend on elements outside the structure. In other words, the result of applying any operation to the elements in the collection will still be in the collection. In programming, this word is used to describe the combination of a function and its context. A closure allows you to access variables in the scope of an outer function even if the outer function has finished executing. A function &quot;closes&quot; or &quot;captures&quot; the state of the environment when it is created. By default, the operator() of the closure class generated by lambda expressions is const. In this case, developers cannot modify any data inside the closure, which ensures that they will not modify the captured values, which is consistent with the mathematical and functional origins of closures.<\/p>\n<\/blockquote>\n\n\n\n<p>The compiler generates a<strong>Closure Class<\/strong>This class<strong>Overload<\/strong>operator() is added so that the closure object can be called like a function. This overloaded operator contains the code of the lambda expression.<\/p>\n\n\n\n<p>Lambda expressions can<strong>capture<\/strong>External variables, which are implemented as member variables of the closure class. Capture can be value capture or reference capture, corresponding to the copying of values and the storage of references in the closure class, respectively.<\/p>\n\n\n\n<p>The closure class has a constructor that initializes the captured outer variables. If it is a value capture, these values are copied to the closure object. If it is a reference capture, the reference of the outer variable is stored.<\/p>\n\n\n\n<p>When a lambda expression is called, the operator() of the closure object is actually called.<\/p>\n\n\n\n<p>Assume the lambda expression is as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>[capture](parameters) -&gt; return_type { body }<\/code><\/pre>\n\n\n\n<p>Here is some pseudo code that a compiler might generate:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u95ed\u5305\u7c7b\u7684\u4f2a\u4ee3\u7801\u53ef\u80fd\u5982\u4e0b\u6240\u793a\uff1a\nclass UniqueClosureName {\nprivate:\n    \/\/ \u6355\u83b7\u7684\u53d8\u91cf\n    capture_type captured_variable;\n\npublic:\n    \/\/ \u6784\u9020\u51fd\u6570\uff0c\u7528\u4e8e\u521d\u59cb\u5316\u6355\u83b7\u7684\u53d8\u91cf\n    UniqueClosureName(capture_type captured) : captured_variable(captured) {}\n\n    \/\/ \u91cd\u8f7d\u7684\u51fd\u6570\u8c03\u7528\u64cd\u4f5c\u7b26\n    return_type operator()(parameter_type parameters) const {\n        \/\/ lambda\u8868\u8fbe\u5f0f\u7684\u4e3b\u4f53\n        body\n    }\n};\n\n\/\/ \u4f7f\u7528\u95ed\u5305\u7c7b\u7684\u5b9e\u4f8b\nUniqueClosureName closure_instance(captured_value);\nauto result = closure_instance(parameters); \/\/ \u8fd9\u76f8\u5f53\u4e8e\u8c03\u7528lambda\u8868\u8fbe\u5f0f<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2. Lambda types and decltype with conditional compilation constexpr (C++17)<\/h3>\n\n\n\n<p>As we know, each lambda expression has its own unique type, which is automatically generated by the compiler. Even if two lambda expressions look exactly the same, their types are different. These types cannot be expressed directly in the code, we use templates and type inference mechanisms to operate and infer them.<\/p>\n\n\n\n<p>The decltype keyword can be used to obtain the type of a lambda expression. In the following example, decltype(lambda) obtains the exact type of the lambda expression. In this way, another variable another_lambda of the same type can be declared and the original lambda can be assigned to it. This feature generally plays an important role in template programming.<\/p>\n\n\n\n<p>Look at the following example of a chef cooking. You don&#039;t know the type of the ingredient yet, but you can use decltype to get the type of the ingredient. The key point is that you can clearly get the type of the return value and mark the return type for the lambda.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>template auto cookDish(T ingredient) -&gt; decltype(ingredient.prepare()) { return ingredient.prepare(); }<\/code><\/pre>\n\n\n\n<p>Furthermore, an important use of decltype in C++ is<strong>Compile time<\/strong>Choose different code paths according to different types, that is,<strong>Conditional compilation<\/strong>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;type_traits&gt;\n\ntemplate &lt;typename T&gt;\nvoid process(T value) {\n    if constexpr (std::is_same&lt;decltype(value), int&gt;::value) {\n        std::cout &lt;&lt; \"\u5904\u7406\u6574\u6570: \" &lt;&lt; value &lt;&lt; std::endl;\n    } else if constexpr (std::is_same&lt;decltype(value), double&gt;::value) {\n        std::cout &lt;&lt; \"\u5904\u7406\u6d6e\u70b9\u6570: \" &lt;&lt; value &lt;&lt; std::endl;\n    } else {\n        std::cout &lt;&lt; \"\u5904\u7406\u5176\u4ed6\u7c7b\u578b: \" &lt;&lt; value &lt;&lt; std::endl;\n    }\n}<\/code><\/pre>\n\n\n\n<p>The following example is about lambda.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n#include &lt;type_traits&gt;\n\n\/\/ \u4e00\u4e2a\u6cdb\u578b\u51fd\u6570\uff0c\u6839\u636e\u4f20\u5165\u7684 lambda \u7c7b\u578b\u6267\u884c\u4e0d\u540c\u7684\u64cd\u4f5c\ntemplate &lt;typename T&gt;\nvoid executeLambda(T lambda) {\n    if constexpr (std::is_same&lt;decltype(lambda), void(*)()&gt;::value) {\n        std::cout &lt;&lt; \"Lambda is a void function with no parameters.\" &lt;&lt; std::endl;\n        lambda();\n    } else if constexpr (std::is_same&lt;decltype(lambda), void(*)(int)&gt;::value) {\n        std::cout &lt;&lt; \"Lambda is a void function taking an int.\" &lt;&lt; std::endl;\n        lambda(10);\n    } else {\n        std::cout &lt;&lt; \"Lambda is of an unknown type.\" &lt;&lt; std::endl;\n    }\n}\n\nint main() {\n    \/\/ Lambda with no parameters\n    auto lambda1 = &#91;]() { std::cout &lt;&lt; \"Hello from lambda1!\" &lt;&lt; std::endl; };\n\n    \/\/ Lambda with one int parameter\n    auto lambda2 = &#91;](int x) { std::cout &lt;&lt; \"Hello from lambda2, x = \" &lt;&lt; x &lt;&lt; std::endl; };\n\n    executeLambda(lambda1);\n    executeLambda(lambda2);\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3. Lambda\u2019s evolution in the new standard<\/h3>\n\n\n\n<p><strong>C++11<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Introducing Lambda Expressions<\/strong>: Lambda expressions were first introduced in the C++11 standard, which can easily define anonymous function objects. The basic form is <a href=\"\/en\/parameters\/\">capture<\/a> -&gt; return_type { body }.<\/li>\n\n\n\n<li><strong>Capture List<\/strong>: Supports capturing external variables by value (=) or reference (&amp;).<\/li>\n<\/ul>\n\n\n\n<p><strong>C++14<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Generic Lambda<\/strong>: Allows the use of the auto keyword in the parameter list, making Lambda work like a template function.<\/li>\n\n\n\n<li><strong>Capture Initialization<\/strong>: Allows the use of initializer expressions in capture lists to create lambda-specific data members.<\/li>\n<\/ul>\n\n\n\n<p><strong>C++17<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Default construction and assignment<\/strong>: The closure type produced by a lambda expression can be default constructible and assignable under certain conditions.<\/li>\n\n\n\n<li><strong>Capture the *this pointer<\/strong>: By capturing *this, you can copy the current object to Lambda by value to avoid the dangling pointer problem.<\/li>\n\n\n\n<li><strong>constexpr Lambda<\/strong>: constexpr Lambda can be used to perform calculations at compile time. It is particularly useful in scenarios such as template metaprogramming and compile-time data generation.<\/li>\n<\/ul>\n\n\n\n<p><strong>C++20<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Template Lambda<\/strong>: Lambda expressions can have template parameter lists, similar to template functions.<\/li>\n\n\n\n<li><strong>More flexible capture lists<\/strong>: Capture lists of the form [=, this] and [&amp;, this] are allowed.<\/li>\n\n\n\n<li><strong>Implicit motion capture<\/strong>: Automatically use move capture when appropriate (only copy and reference capture are supported in C++14).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4. State-preserving Lambda<\/h3>\n\n\n\n<p>In the following example, the value and reference capture variable x is the key to keep the state of Lambda. It can also capture and maintain its own state.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;iostream&gt;\n\nint main() {\n    int x0 = 10, x1 = 20, count = 0;\n    auto addX = &#91;x0, &amp;x1, count](int y) mutable {\n        count++;\n        return x0 + x1 + y + count;\n    };\n\n    std::cout &lt;&lt; addX(5) &lt;&lt; std::endl;  \/\/ \u8f93\u51fa 36\n    std::cout &lt;&lt; addX(5) &lt;&lt; std::endl;  \/\/ \u8f93\u51fa 37\n    std::cout &lt;&lt; addX(5) &lt;&lt; std::endl;  \/\/ \u8f93\u51fa 38\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">5. Optimization and Lambda<\/h3>\n\n\n\n<p>Why is Lambda good?<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Inline optimization: Lambda is generally short, and inline optimization reduces function call overhead.<\/li>\n\n\n\n<li>Avoid unnecessary object creation: Reference capture and move semantics can reduce the overhead of transferring and copying large objects.<\/li>\n\n\n\n<li>Deferred computation: Calculations are performed only when the result is actually needed.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">6. Integration with other programming paradigms<\/h3>\n\n\n\n<h3 class=\"wp-block-heading\">Functional Programming<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class StringBuilder {\nprivate:\n    std::string str;\n\npublic:\n    StringBuilder&amp; append(const std::string&amp; text) {\n        str += text;\n        return *this;\n    }\n\n    const std::string&amp; toString() const {\n        return str;\n    }\n};\n\n\/\/ \u4f7f\u7528\nStringBuilder builder;\nbuilder.append(\"Hello, \").append(\"world! \");\nstd::cout &lt;&lt; builder.toString() &lt;&lt; std::endl;  \/\/ \u8f93\u51fa \"Hello, world! \"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Pipeline call<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;ranges&gt;\n#include &lt;vector&gt;\n#include &lt;iostream&gt;\n\nint main() {\n    std::vector&lt;int&gt; vec = {1, 2, 3, 4, 5};\n\n    auto pipeline = vec \n                    | std::views::transform(&#91;](int x) { return x * 2; })\n                    | std::views::filter(&#91;](int x) { return x &gt; 5; });\n\n    for (int n : pipeline) std::cout &lt;&lt; n &lt;&lt; \" \"; \/\/ \u8f93\u51fa\u6ee1\u8db3\u6761\u4ef6\u7684\u5143\u7d20\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">7. Lambda and Exception Handling<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>auto divide = &#91;](double numerator, double denominator) {\n    if (denominator == 0) {\n        throw std::runtime_error(\"Division by zero.\");\n    }\n    return numerator \/ denominator;\n};\n\ntry {\n    auto result = divide(10.0, 0.0);\n} catch (const std::runtime_error&amp; e) {\n    std::cerr &lt;&lt; \"Caught exception: \" &lt;&lt; e.what() &lt;&lt; std::endl;\n}<\/code><\/pre>\n\n\n\n<p>Although a lambda expression itself cannot contain a try-catch block (before C++20), exceptions can be caught outside of a lambda expression. That is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auto riskyTask = &#91;]() {\n    \/\/ \u5047\u8bbe\u8fd9\u91cc\u6709\u53ef\u80fd\u629b\u51fa\u5f02\u5e38\u7684\u4ee3\u7801\n};\n\ntry {\n    riskyTask();\n} catch (...) {\n    \/\/ \u5904\u7406\u5f02\u5e38\n}<\/code><\/pre>\n\n\n\n<p>Starting from C++20, lambda expressions support exception specifications.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Before C++17, you could use dynamic exception specifications in function declarations, such as throw(Type), to specify the types of exceptions that a function might throw. However, this practice was deprecated in C++17 and completely removed in C++20. Instead, the noexcept keyword is used to indicate whether a function throws an exception.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>auto lambdaNoExcept = []() noexcept { \/\/ This guarantees that no exception will be thrown};<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Advanced<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Lambda and noexcept (C++11)<\/h3>\n\n\n\n<p>noexcept can be used to specify whether a lambda expression is guaranteed not to throw exceptions.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auto lambda = []() noexcept { \/\/ The code here is guaranteed not to throw an exception};<\/code><\/pre>\n\n\n\n<p>When the compiler knows that a function will not throw exceptions, it can generate more optimized code.<\/p>\n\n\n\n<p>You can also explicitly throw exceptions to improve code readability, but it&#039;s the same as not writing any.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auto lambdaWithException = []() noexcept(false) { \/\/ Code here may throw an exception};<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2. Template parameters in Lambda (C++20)<\/h3>\n\n\n\n<p>In C++20, Lambda expressions have received an important enhancement, which is the support of template parameters. How cool!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auto lambda = &#91;]&lt;typename T&gt;(T param) {\n    \/\/ \u4f7f\u7528\u6a21\u677f\u53c2\u6570T\u7684\u4ee3\u7801\n};\nauto print = &#91;]&lt;typename T&gt;(const T&amp; value) {\n    std::cout &lt;&lt; value &lt;&lt; std::endl;\n};\n\nprint(10);        \/\/ \u6253\u5370\u4e00\u4e2a\u6574\u6570\nprint(\"Hello\");   \/\/ \u6253\u5370\u4e00\u4e2a\u5b57\u7b26\u4e32<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3. Lambda Reflection<\/h3>\n\n\n\n<p>I don\u2019t know, I\u2019ll write about it later.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4. Cross-platform and ABI issues<\/h3>\n\n\n\n<p>I don\u2019t know, I\u2019ll write about it later.<\/p>","protected":false},"excerpt":{"rendered":"<p>\u6211\u4e5f\u662f\u83dc\u9e21QAQ\uff0c\u6d45\u6d45\u5206\u4eab\u4e00\u4e0b\u5b66\u4e60C++Lambda\u7684\u7b14\u8bb0\u3002\u501f\u6b64\u7ba1\u4e2d\u7aa5\u8c79\uff0c\u5b9b\u5982\u900f\u8fc7\u72ed\u7f1d\u7aa5\u63a2\u77e5\u4e4e\u5927\u4f6c\u4eec\u9068\u6e38\u4e8e\u667a\u6167 [&hellip;]<\/p>","protected":false},"author":1,"featured_media":65,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[53],"tags":[],"class_list":["post-1401","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tech"],"_links":{"self":[{"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/posts\/1401","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/comments?post=1401"}],"version-history":[{"count":1,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/posts\/1401\/revisions"}],"predecessor-version":[{"id":1402,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/posts\/1401\/revisions\/1402"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/media\/65"}],"wp:attachment":[{"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/media?parent=1401"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/categories?post=1401"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/tags?post=1401"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}