{"id":5958,"date":"2020-08-07T06:04:01","date_gmt":"2020-08-07T06:04:01","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/more-lambdas-features-with-c-20\/"},"modified":"2023-06-26T09:46:40","modified_gmt":"2023-06-26T09:46:40","slug":"more-lambdas-features-with-c-20","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/more-lambdas-features-with-c-20\/","title":{"rendered":"More Lambda Features with C++20"},"content":{"rendered":"<p>Lambdas in C++20 can be default-constructed and support copy-assignment when they have no state. Lambdas can be used in unevaluated contexts. Additionally, they detect when you implicitly copy the <span style=\"font-family: courier new, courier;\">this<\/span> pointer. This means a significant cause of undefined behavior with lambdas is gone.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5945\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/07\/TimelineCpp20CoreLanguage.png\" alt=\"TimelineCpp20CoreLanguage\" width=\"650\" height=\"259\" style=\"display: block; margin-left: auto; margin-right: auto;\" \/><\/p>\n<p>I want to start with the last feature of the enumeration. The compiler detects the undefined behavior when you implicitly copy the <span style=\"font-family: courier new, courier;\">this<\/span> pointer. Okay, what does undefined behavior mean? <strong>With undefined behavior, there are no restrictions on the behavior of the program, and you have, therefore, no guarantee of what can happen.<\/strong><\/p>\n<p>I like to say in my seminars: When you have undefined behavior, your program has catch-fire semantics. This means your computer can even catch fire. In former days undefined behavior was described more rigorously: with undefined behavior, you can launch a cruise missile.&nbsp;Anyway, when you have undefined behavior, there is only one action left: fix the undefined behavior.<\/p>\n<p>In the next section, I intentionally cause undefined behavior.<\/p>\n<h2>Implicitly Copy of the <span style=\"font-family: 'courier new', courier;\">this<\/span> Pointer<\/h2>\n<p>The following program implicitly captures the <span style=\"font-family: 'courier new', courier;\">this<\/span> pointer by copy.<\/p>\n<p>&nbsp;<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ lambdaCaptureThis.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Lambda {\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> foo() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> [<span style=\"color: #555555;\">=<\/span>] { std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> s <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl; };   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span> \r\n    }\r\n    std<span style=\"color: #555555;\">::<\/span>string s <span style=\"color: #555555;\">=<\/span> <span style=\"color: #cc3300;\">\"lambda\"<\/span>;\r\n     <span style=\"color: #555555;\">~<\/span>Lambda() {\r\n        std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Goodbye\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    }\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #cc00ff;\">makeLambda<\/span>() {                                               \r\n    Lambda lambda;                                     <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>                               \r\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> lambda.foo();\r\n}                                                      <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> lam <span style=\"color: #555555;\">=<\/span> makeLambda();                                \r\n    lam();                                             <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>                                                               \r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The compilation of the program works as expected, but this does not hold for the execution of the program.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5954\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/LambdaCaptureThis.png\" alt=\"LambdaCaptureThis\" width=\"550\" height=\"197\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/LambdaCaptureThis.png 733w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/LambdaCaptureThis-300x107.png 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/p>\n<p>Do you spot the issue in th<span>e <\/span>program <span style=\"font-family: 'courier new', courier;\">lambdaCaptureThis.cpp<\/span>? The member function foo (1) returns the lambda<span style=\"font-family: 'courier new', courier;\"> [=] { std::cout &lt;&lt; s &lt;&lt; std::endl; }<\/span> having an implicit copy of the <span style=\"font-family: 'courier new', courier;\">this<\/span> pointer. This implicit copy is no issue in (2) but becomes an issue at the end of the scope. The end of the scope means the end of the lifetime of the local <span style=\"font-family: 'courier new', courier;\">lambda<\/span> (3). Consequently, the call lam() (4) triggers undefined behavior.<\/p>\n<p>A C++20 compiler must, in this case, write a warning. Here is the output with the <a href=\"https:\/\/godbolt.org\/\">Compiler Explorer <\/a>and GCC.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5955\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/LambdaCaptureThisWarning.png\" alt=\"LambdaCaptureThisWarning\" width=\"650\" height=\"128\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/LambdaCaptureThisWarning.png 1054w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/LambdaCaptureThisWarning-300x59.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/LambdaCaptureThisWarning-1024x202.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/LambdaCaptureThisWarning-768x152.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>The two missing lambdas features of C++20 sound not so thrilling:&nbsp;Lambdas in C++20 can be default-constructed and support copy-assignment when they have no state. Lambdas can be used in unevaluated contexts. Before I present both features together, I have to make a detour: What does unevaluated context mean?<\/p>\n<\/p>\n<h2>Unevaluated Context<\/h2>\n<p>The following code snippet has a function declaration and a function definition.&nbsp;<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">add1<\/span>(<span style=\"color: #007788; font-weight: bold;\">int<\/span>, <span style=\"color: #007788; font-weight: bold;\">int<\/span>);                       <span style=\"color: #0099ff; font-style: italic;\">\/\/ declaration<\/span>\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">add2<\/span>(<span style=\"color: #007788; font-weight: bold;\">int<\/span> a, <span style=\"color: #007788; font-weight: bold;\">int<\/span> b) { <span style=\"color: #006699; font-weight: bold;\">return<\/span> a <span style=\"color: #555555;\">+<\/span> b; }  <span style=\"color: #0099ff; font-style: italic;\">\/\/ definition<\/span>\r\n   \r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: 'courier new', courier;\">add1<\/span> declares a function, but <span style=\"font-family: 'courier new', courier;\">add2<\/span> defines it. This means if you use <span style=\"font-family: 'courier new', courier;\">add1<\/span> in an evaluated context, such as invoking it, you get a link-time error. The critical observation is that you can use <span style=\"font-family: 'courier new', courier;\">add1<\/span> in unevaluated contexts such as <span style=\"font-family: 'courier new', courier;\">typeid<\/span>, or <span style=\"font-family: 'courier new', courier;\">decltype<\/span>. Both operators accept unevaluated operands.<\/p>\n<p>&nbsp;<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ unevaluatedContext.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;typeinfo&gt;  <\/span><span style=\"color: #0099ff; font-style: italic;\">\/\/ typeid<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">add1<\/span>(<span style=\"color: #007788; font-weight: bold;\">int<\/span>, <span style=\"color: #007788; font-weight: bold;\">int<\/span>);                       <span style=\"color: #0099ff; font-style: italic;\">\/\/ declaration<\/span>\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">add2<\/span>(<span style=\"color: #007788; font-weight: bold;\">int<\/span> a, <span style=\"color: #007788; font-weight: bold;\">int<\/span> b) { <span style=\"color: #006699; font-weight: bold;\">return<\/span> a <span style=\"color: #555555;\">+<\/span> b; }  <span style=\"color: #0099ff; font-style: italic;\">\/\/ definition<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"typeid(add1).name(): \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #006699; font-weight: bold;\">typeid<\/span>(add1).name() <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl; <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n    \r\n    decltype(<span style=\"color: #555555;\">*<\/span>add1) add <span style=\"color: #555555;\">=<\/span> add2;                                               <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"add(2000, 20): \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> add(<span style=\"color: #ff6600;\">2000<\/span>, <span style=\"color: #ff6600;\">20<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: 'courier new', courier;\">typeid(add1).name()<\/span>&nbsp;(1) returns a string representation of the type, and <span style=\"font-family: 'courier new', courier;\">decltype<\/span>&nbsp;(2) deduces the type of its argument.<\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5956\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/unevaluatedContext.png\" alt=\"unevaluatedContext\" width=\"350\" height=\"199\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/unevaluatedContext.png 404w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/unevaluatedContext-300x171.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<h2>Stateless Lambdas can be default-constructed and copy-assigned<\/h2>\n<h2>Lambdas can be used in unevaluated contexts<\/h2>\n<p>Admittedly, this is quite a long title. Maybe the term stateless lambda is new to you. A stateless lambda is a lambda that captures nothing from its environment. Or, to put it the other way around. A stateless lambda is a lambda where the initial brackets&nbsp;<span style=\"font-family: 'courier new', courier;\">[]<\/span> in the lambda definition are empty. For example, the lambda expression <span style=\"font-family: 'courier new', courier;\">auto add = [ ](int a, int b) { return a + b; }; <\/span>is stateless.<\/p>\n<p>When you combine the features, you get lambdas, which are pretty handy.&nbsp;<\/p>\n<p>Before I show you the example, I must add a few remarks.&nbsp;<span style=\"font-family: 'courier new', courier;\">std::set<\/span> such as all other ordered associative containers from the standard template library&nbsp; (<span style=\"font-family: 'courier new', courier;\">std::map, std::multiset<\/span>,&nbsp; and <span style=\"font-family: 'courier new', courier;\">std::multimap<\/span>) use per-default&nbsp;<span style=\"font-family: 'courier new', courier;\">std::less<\/span>&nbsp;to sort the keys.&nbsp;<span style=\"font-family: 'courier new', courier;\">std::less<\/span> guarantees that all keys are ordered lexicographically in ascending order. The declaration of <span style=\"font-family: courier new, courier;\">std::set<\/span>&nbsp; on <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/container\/set\">cppreference.com<\/a> shows you this ordering behavior.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #006699; font-weight: bold;\">template<\/span><span style=\"color: #555555;\">&lt;<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Key<\/span>,\r\n    <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Compare<\/span> <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>less<span style=\"color: #555555;\">&lt;<\/span>Key<span style=\"color: #555555;\">&gt;<\/span>,\r\n    <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Allocator<\/span> <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>allocator<span style=\"color: #555555;\">&lt;<\/span>Key<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #555555;\">&gt;<\/span> <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">set<\/span>;\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Now, let me play with the ordering in the following example.<\/p>\n<p>&nbsp;<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ lambdaUnevaluatedContext.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;cmath&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;memory&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;set&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> Cont<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> printContainer(<span style=\"color: #006699; font-weight: bold;\">const<\/span> Cont<span style=\"color: #555555;\">&amp;<\/span> cont) {\r\n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> c<span style=\"color: #555555;\">:<\/span> cont) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> c <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"  \"<\/span>;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>;\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> main() {\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>set<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>string<span style=\"color: #555555;\">&gt;<\/span> set1 <span style=\"color: #555555;\">=<\/span> {<span style=\"color: #cc3300;\">\"scott\"<\/span>, <span style=\"color: #cc3300;\">\"Bjarne\"<\/span>, <span style=\"color: #cc3300;\">\"Herb\"<\/span>, <span style=\"color: #cc3300;\">\"Dave\"<\/span>, <span style=\"color: #cc3300;\">\"michael\"<\/span>};\r\n    printContainer(set1);\r\n    \r\n    <span style=\"color: #006699; font-weight: bold;\">using<\/span> SetDecreasing <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>set<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>string, decltype([](<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> l, <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> r){ <span style=\"color: #006699; font-weight: bold;\">return<\/span> l <span style=\"color: #555555;\">&gt;<\/span> r; })<span style=\"color: #555555;\">&gt;<\/span>;           <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n    SetDecreasing set2 <span style=\"color: #555555;\">=<\/span> {<span style=\"color: #cc3300;\">\"scott\"<\/span>, <span style=\"color: #cc3300;\">\"Bjarne\"<\/span>, <span style=\"color: #cc3300;\">\"Herb\"<\/span>, <span style=\"color: #cc3300;\">\"Dave\"<\/span>, <span style=\"color: #cc3300;\">\"michael\"<\/span>};\r\n    printContainer(set2);     <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n\r\n    <span style=\"color: #006699; font-weight: bold;\">using<\/span> SetLength <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>set<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>string, decltype([](<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> l, <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> r){ <span style=\"color: #006699; font-weight: bold;\">return<\/span> l.size() <span style=\"color: #555555;\">&lt;<\/span> r.size(); })<span style=\"color: #555555;\">&gt;<\/span>; <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n    SetLength set3 <span style=\"color: #555555;\">=<\/span> {<span style=\"color: #cc3300;\">\"scott\"<\/span>, <span style=\"color: #cc3300;\">\"Bjarne\"<\/span>, <span style=\"color: #cc3300;\">\"Herb\"<\/span>, <span style=\"color: #cc3300;\">\"Dave\"<\/span>, <span style=\"color: #cc3300;\">\"michael\"<\/span>};\r\n    printContainer(set3);     <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>set<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> set4 <span style=\"color: #555555;\">=<\/span> {<span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">10<\/span>, <span style=\"color: #ff6600;\">5<\/span>, <span style=\"color: #ff6600;\">3<\/span>, <span style=\"color: #ff6600;\">100<\/span>, <span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">25<\/span>};\r\n    printContainer(set4);\r\n\r\n    <span style=\"color: #006699; font-weight: bold;\">using<\/span> setAbsolute <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>set<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span>, decltype([](<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> l, <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> r){ <span style=\"color: #006699; font-weight: bold;\">return<\/span>  std<span style=\"color: #555555;\">::<\/span>abs(l)<span style=\"color: #555555;\">&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>abs(r); })<span style=\"color: #555555;\">&gt;<\/span>; <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n    setAbsolute set5 <span style=\"color: #555555;\">=<\/span> {<span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">10<\/span>, <span style=\"color: #ff6600;\">5<\/span>, <span style=\"color: #ff6600;\">3<\/span>, <span style=\"color: #ff6600;\">100<\/span>, <span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">25<\/span>};\r\n    printContainer(set5);    <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>;\r\n    \r\n}\r\n \r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: 'courier new', courier;\">set1<\/span> and <span style=\"font-family: 'courier new', courier;\">set4<\/span> sort their keys in ascending order. <span style=\"font-family: 'courier new', courier;\">set2<\/span>, <span style=\"font-family: 'courier new', courier;\">set3<\/span>, and <span style=\"font-family: 'courier new', courier;\">set5<\/span> uniquely use a lambda in an unevaluated context. The <span style=\"font-family: 'courier new', courier;\">using<\/span> keyword (1) declares a type alias, which is used in the following line (2) to define the sets. Creating the set causes the call of the default constructor of the stateless lambda.<\/p>\n<p>Thanks to the Compiler Explorer and GCC, here is the program&#8217;s output.<\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5957\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/lambdaUnevaluatedContext.png\" alt=\"lambdaUnevaluatedContext\" width=\"350\" height=\"142\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/lambdaUnevaluatedContext.png 418w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/08\/lambdaUnevaluatedContext-300x121.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<p>When you study the output of the program, you may be surprised. The special set3, which uses the lambda <span style=\"font-family: 'courier new', courier;\">[](const auto&amp; l, const auto&amp; r){ return l.size() &lt; r.size(); }&nbsp;<\/span>as a predicate, ignores the name &#8220;<span style=\"font-family: 'courier new', courier;\">Dave&#8221;. <\/span>The reason is simple. &#8220;<span style=\"font-family: 'courier new', courier;\">Dave<\/span>&#8221; has the same size as &#8220;<span style=\"font-family: 'courier new', courier;\">Herb<\/span>&#8220;, which was added first. <span style=\"font-family: 'courier new', courier;\">std::set<\/span> supports unique keys, and the keys are identical using the special predicate. If I had used&nbsp;<span style=\"font-family: 'courier new', courier;\">std::multiset, <\/span>this wouldn&#8217;t have happened.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>Only a few smaller features in C++20 are left. The little features include the new attributes <span style=\"font-family: 'courier new', courier;\">[[likely]<\/span>] and <span style=\"font-family: 'courier new', courier;\">[[unlikely]]<\/span>, and most of <span style=\"font-family: 'courier new', courier;\">volatile<\/span> was deprecated.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lambdas in C++20 can be default-constructed and support copy-assignment when they have no state. Lambdas can be used in unevaluated contexts. Additionally, they detect when you implicitly copy the this pointer. This means a significant cause of undefined behavior with lambdas is gone.<\/p>\n","protected":false},"author":21,"featured_media":5945,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[459],"class_list":["post-5958","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-lambdas"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5958","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=5958"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5958\/revisions"}],"predecessor-version":[{"id":6731,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5958\/revisions\/6731"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5945"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5958"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5958"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5958"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}