{"id":5661,"date":"2019-04-11T20:38:56","date_gmt":"2019-04-11T20:38:56","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-insights-lambdas\/"},"modified":"2023-06-26T10:12:20","modified_gmt":"2023-06-26T10:12:20","slug":"c-insights-lambdas","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-insights-lambdas\/","title":{"rendered":"C++ Insights &#8211; Lambdas"},"content":{"rendered":"<p>Honestly, many programmers in my classes have issues with the syntactic sugar of lambdas. Desugaring lambdas with C++ Insights helps quite often.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5660\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/04\/05-lambdas.png\" alt=\"05 lambdas\" width=\"700\" height=\"394\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/04\/05-lambdas.png 1280w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/04\/05-lambdas-300x169.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/04\/05-lambdas-1024x576.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/04\/05-lambdas-768x432.png 768w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/p>\n<h2>Lambdas<\/h2>\n<p>Lambdas in C++ seems to be the most interesting new language feature. My opinion is based on all the issue reports and emails I got for C++ Insights so far.<\/p>\n<p>They allow us to capture variables in different ways. Due to their lightweight syntax, it\u2019s easy to create new functions like objects. In case, you never heard of it, lambdas are essentially classes with a call operator. The lambda body we provide is then the body of the call operator. For starters that should be it. Actually, lambdas are one of the reasons I created C++ Insights. It can show this transformation which, at least for me, makes it easier to explain. But see for <a href=\"https:\/\/cppinsights.io\/lnk?code=aW50IG1haW4oKQp7CiAgY2hhciBjezF9OwogIAogIGF1dG8gbCA9IFs9XSAoKSB7IHJldHVybiBjOyB9OwoKICByZXR1cm4gbCgpOwp9&amp;std=cpp17&amp;rev=1.0\">yourself<\/a>:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">char<\/span> c{<span class=\"hljs-number\">1<\/span>};\r\n  \r\n  <span class=\"hljs-keyword\">auto<\/span> l = [=] () { <span class=\"hljs-keyword\">return<\/span> c; };\r\n\r\n  <span class=\"hljs-keyword\">return<\/span> l();\r\n}<\/code><\/pre>\n<h3>Capture Options<\/h3>\n<p>Things get more interesting if we start talking about the capture options. A variable that is captured by reference becomes a reference member of the lambdas class. Have a close look at the signature of the call operator. It says const. However, I can still modify x. It\u2019s just a reference and not a const reference as you can see in <a href=\"https:\/\/cppinsights.io\/lnk?code=aW50IG1haW4oKQp7CiAgY2hhciB4ezF9OwogIAogIGF1dG8gbCA9IFsmXSAoKSB7IAogICAgeCA9IDE7CiAgfTsKfQ==&amp;std=cpp17&amp;rev=1.0\">C++ Insights<\/a>:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">char<\/span> x{<span class=\"hljs-number\">1<\/span>};\r\n  \r\n  <span class=\"hljs-keyword\">auto<\/span> l = [&amp;] () { \r\n    x = <span class=\"hljs-number\">1<\/span>;\r\n  };\r\n}\r\n<\/code><\/pre>\n<p>Things change if we capture by copy. Then, the captured variable is a copy. Now the const matters, we can\u2019t modify x without adding mutable to the <a href=\"https:\/\/cppinsights.io\/lnk?code=aW50IG1haW4oKQp7CiAgY2hhciBjezF9OwogIAogIGF1dG8gbCA9IFs9XSAoKSB7IHJldHVybiBjOyB9OwogIAogIGF1dG8gbDIgPSBbPV0gKCkgbXV0YWJsZSB7IAogICAgYyA9IDE7CiAgICAKICAgIHJldHVybiBjOwogIH07Cn0=&amp;std=cpp17&amp;rev=1.0\">lambda definition<\/a>:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">char<\/span> c{<span class=\"hljs-number\">1<\/span>};\r\n  \r\n  <span class=\"hljs-keyword\">auto<\/span> l = [=] () { <span class=\"hljs-keyword\">return<\/span> c; };\r\n  \r\n  <span class=\"hljs-keyword\">auto<\/span> l2 = [=] () <span class=\"hljs-keyword\">mutable<\/span> { \r\n    c = <span class=\"hljs-number\">1<\/span>;\r\n    \r\n    <span class=\"hljs-keyword\">return<\/span> c;\r\n  };\r\n}\r\n<\/code><\/pre>\n<p>Knowing that a class is behind a lambda enables us to think a bit more about things, like for example the size of a lambda. Copy captures increase the size by their size plus eventually padding. To save some bytes the ordering of the captures matters as you can see <a href=\"https:\/\/cppinsights.io\/lnk?code=aW50IG1haW4oKQp7CiAgY2hhciBjOwogIGludCB4OwogIGNoYXIgYjsKICAKICBhdXRvIGwgPSBbPV0gKCkgbXV0YWJsZSB7IAogICAgYyA9IDEsCiAgICB4ID0gMjsKICAgIGIgPSAzOwogIH07CiAgCiAgc3RhdGljX2Fzc2VydChzaXplb2YobCkgPT0gc2l6ZW9mKGludCkqMyk7CiAgCiAgYXV0byBsMiA9IFs9XSAoKSBtdXRhYmxlIHsgCiAgICB4ID0gMjsKICAgIGMgPSAxLAogICAgYiA9IDM7CiAgfTsKICAKICBzdGF0aWNfYXNzZXJ0KHNpemVvZihsMikgPT0gc2l6ZW9mKGludCkqMik7Cn0=&amp;std=cpp17&amp;rev=1.0\">here<\/a>:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">char<\/span> c;\r\n  <span class=\"hljs-keyword\">int<\/span> x;\r\n  <span class=\"hljs-keyword\">char<\/span> b;\r\n  \r\n  <span class=\"hljs-keyword\">auto<\/span> l = [=] () <span class=\"hljs-keyword\">mutable<\/span> { \r\n    c = <span class=\"hljs-number\">1<\/span>,\r\n    x = <span class=\"hljs-number\">2<\/span>;\r\n    b = <span class=\"hljs-number\">3<\/span>;\r\n  };\r\n  \r\n  <span class=\"hljs-keyword\">static_assert<\/span>(<span class=\"hljs-keyword\">sizeof<\/span>(l) == <span class=\"hljs-keyword\">sizeof<\/span>(<span class=\"hljs-keyword\">int<\/span>)*<span class=\"hljs-number\">3<\/span>);\r\n  \r\n  <span class=\"hljs-keyword\">auto<\/span> l2 = [=] () <span class=\"hljs-keyword\">mutable<\/span> { \r\n    x = <span class=\"hljs-number\">2<\/span>;\r\n    c = <span class=\"hljs-number\">1<\/span>,\r\n    b = <span class=\"hljs-number\">3<\/span>;\r\n  };\r\n  \r\n  <span class=\"hljs-keyword\">static_assert<\/span>(<span class=\"hljs-keyword\">sizeof<\/span>(l2) == <span class=\"hljs-keyword\">sizeof<\/span>(<span class=\"hljs-keyword\">int<\/span>)*<span class=\"hljs-number\">2<\/span>);\r\n}\r\n<\/code><\/pre>\n<p>However, please note that the order of the members in the class is unspecified.<\/p>\n<p>Another thing to watch out for is lambdas containing captures by reference. The variables these references point to, need to be valid when the lambda is invoked otherwise you end up with a dangling reference. Here is such an example:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">auto<\/span> <span class=\"hljs-title\">Lambda<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">int<\/span> x{};\r\n  \r\n  <span class=\"hljs-keyword\">return<\/span> [&amp;]{ <span class=\"hljs-keyword\">return<\/span> x; };\r\n}\r\n\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  Lambda()();\r\n}\r\n<\/code><\/pre>\n<p>I think it becomes pretty clear with a look at <a href=\"https:\/\/cppinsights.io\/lnk?code=YXV0byBMYW1iZGEoKQp7CiAgaW50IHh7fTsKICAKICByZXR1cm4gWyZdeyByZXR1cm4geDsgfTsKfQoKaW50IG1haW4oKQp7CiAgTGFtYmRhKCkoKTsKfQ==&amp;std=cpp17&amp;rev=1.0\">C++ Insights<\/a>:<\/p>\n<pre><code class=\"language-C++\">__<span class=\"hljs-function\">lambda_5_10 <span class=\"hljs-title\">Lambda<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">int<\/span> x = {};\r\n    \r\n  <span class=\"hljs-keyword\">class<\/span> __lambda_5_10\r\n  {\r\n    <span class=\"hljs-keyword\">int<\/span> &amp; x;\r\n    <span class=\"hljs-keyword\">public<\/span>: <span class=\"hljs-keyword\">inline<\/span> <span class=\"hljs-comment\">\/*constexpr *\/<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">operator<\/span><span class=\"hljs-params\">()<\/span><span class=\"hljs-params\">()<\/span> <span class=\"hljs-keyword\">const<\/span>\r\n    <\/span>{\r\n      <span class=\"hljs-keyword\">return<\/span> x;\r\n    }\r\n    \r\n    <span class=\"hljs-keyword\">public<\/span>: __lambda_5_10(<span class=\"hljs-keyword\">int<\/span> &amp; _x)\r\n    : x{_x}\r\n    {}\r\n    \r\n  } __lambda_5_10{x};\r\n  \r\n  <span class=\"hljs-keyword\">return<\/span> __lambda_5_10;\r\n}\r\n\r\n\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  Lambda().<span class=\"hljs-keyword\">operator<\/span>()();\r\n}\r\n<\/code><\/pre>\n<p>You already knew that? Excellent! You are either careful or use copy captures because then you are safe? Well, let\u2019s see.<\/p>\n<p>How about this nice copy capture <a href=\"https:\/\/cppinsights.io\/lnk?code=YXV0byBMYW1iZGEoKQp7CiAgaW50ICB5e307CiAgaW50KiB4eyZ5fTsKCiAgcmV0dXJuIFs9XXsgcmV0dXJuIHg7IH07Cn0KCmludCBtYWluKCkKewogIGF1dG8geCA9IExhbWJkYSgpKCk7Cn0=&amp;std=cpp17&amp;rev=1.0\">example<\/a>:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">auto<\/span> <span class=\"hljs-title\">Lambda<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">int<\/span>  y{};\r\n  <span class=\"hljs-keyword\">int<\/span>* x{&amp;y};\r\n\r\n  <span class=\"hljs-keyword\">return<\/span> [=]{ <span class=\"hljs-keyword\">return<\/span> x; };\r\n}\r\n\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">auto<\/span> x = Lambda()();\r\n}\r\n<\/code><\/pre>\n<p>Here we capture only by copy, but we still return something on the stack. The pointer we copy-capture is still a pointer pointing to something on the stack which is no longer valid after we left <code>Lambda<\/code>.<\/p>\n<\/p>\n<h3>Deeper Insights<\/h3>\n<p>At this point we covered templates, variadic templates, fold expressions, constexpr if and lambdas. We have seen how C++ Insights can show us the internals or the details. How about using them all together? Like this:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">include<\/span> <span class=\"hljs-string\">&lt;string&gt;<\/span><\/span>\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">include<\/span> <span class=\"hljs-string\">&lt;type_traits&gt;<\/span><\/span>\r\n\r\n<span class=\"hljs-keyword\">template<\/span> &lt;<span class=\"hljs-keyword\">typename<\/span>... Ts&gt;\r\n<span class=\"hljs-built_in\">std<\/span>::<span class=\"hljs-function\"><span class=\"hljs-built_in\">string<\/span> <span class=\"hljs-title\">stringify<\/span><span class=\"hljs-params\">(Ts&amp;&amp;... args)<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">auto<\/span> convert = [](<span class=\"hljs-keyword\">auto<\/span>&amp;&amp; arg) {\r\n    <span class=\"hljs-keyword\">using<\/span> TT = <span class=\"hljs-built_in\">std<\/span>::<span class=\"hljs-keyword\">remove_reference_t<\/span>&lt;<span class=\"hljs-keyword\">decltype<\/span>(arg)&gt;;\r\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">if<\/span> <span class=\"hljs-title\">constexpr<\/span><span class=\"hljs-params\">(<span class=\"hljs-built_in\">std<\/span>::is_same_v&lt;TT, <span class=\"hljs-built_in\">std<\/span>::<span class=\"hljs-built_in\">string<\/span>&gt;)<\/span> <\/span>{\r\n      <span class=\"hljs-keyword\">return<\/span> arg;\r\n    } <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">if<\/span> <span class=\"hljs-title\">constexpr<\/span><span class=\"hljs-params\">(<span class=\"hljs-built_in\">std<\/span>::is_array_v&lt; TT &gt;)<\/span> <\/span>{\r\n      <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-built_in\">std<\/span>::<span class=\"hljs-built_in\">string<\/span>{arg};\r\n    } <span class=\"hljs-keyword\">else<\/span> {\r\n      <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-built_in\">std<\/span>::to_string(arg);\r\n    }\r\n  };\r\n  \r\n  <span class=\"hljs-built_in\">std<\/span>::<span class=\"hljs-built_in\">string<\/span> ret{};\r\n  <span class=\"hljs-keyword\">auto<\/span> concat = [](<span class=\"hljs-built_in\">std<\/span>::<span class=\"hljs-built_in\">string<\/span>&amp; dst, <span class=\"hljs-keyword\">auto<\/span>&amp;&amp; arg) {\r\n    dst += arg;\r\n  };\r\n  \r\n  (..., concat(ret, convert(args)));\r\n   \r\n  <span class=\"hljs-keyword\">return<\/span> ret;\r\n}\r\n\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-built_in\">std<\/span>::<span class=\"hljs-built_in\">string<\/span> hello{<span class=\"hljs-string\">\"hello \"<\/span>};\r\n  <span class=\"hljs-keyword\">auto<\/span> s = stringify(<span class=\"hljs-string\">\"A \"<\/span>, hello, <span class=\"hljs-number\">2<\/span>, <span class=\"hljs-string\">\" \"<\/span>, <span class=\"hljs-string\">\"C++ Insights\"<\/span>);\r\n\r\n  <span class=\"hljs-built_in\">printf<\/span>(<span class=\"hljs-string\">\"%s\\n\"<\/span>, s.c_str());\r\n}\r\n<\/code><\/pre>\n<p>Here, we have a variadic template that contains two lambdas. The first one (convert) does the conversion from anything into a string. This is similar to what we had in the previous post. The second one concatenates all arguments. Then in the line,&nbsp;<code>(..., concat(ret, convert(args)));<\/code> all arguments get expanded by the fold expression and with the use of the comma operator. Neat and reasonably small, at least in my opinion. How does this code look internally? Have a look at <a href=\"https:\/\/cppinsights.io\/lnk?code=I2luY2x1ZGUgPHN0cmluZz4KI2luY2x1ZGUgPHR5cGVfdHJhaXRzPgoKdGVtcGxhdGUgPHR5cGVuYW1lLi4uIFRzPgpzdGQ6OnN0cmluZyBzdHJpbmdpZnkoVHMmJi4uLiBhcmdzKQp7CiAgYXV0byBjb252ZXJ0ID0gW10oYXV0byYmIGFyZykgewogICAgdXNpbmcgVFQgPSBzdGQ6OnJlbW92ZV9yZWZlcmVuY2VfdDxkZWNsdHlwZShhcmcpPjsKICAgIGlmIGNvbnN0ZXhwcihzdGQ6OmlzX3NhbWVfdjxUVCwgc3RkOjpzdHJpbmc+KSB7CiAgICAgIHJldHVybiBhcmc7CiAgICB9IGVsc2UgaWYgY29uc3RleHByKHN0ZDo6aXNfYXJyYXlfdjwgVFQgPikgewogICAgICByZXR1cm4gc3RkOjpzdHJpbmd7YXJnfTsKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybiBzdGQ6OnRvX3N0cmluZyhhcmcpOwogICAgfQogIH07CiAgCiAgc3RkOjpzdHJpbmcgcmV0e307CiAgYXV0byBjb25jYXQgPSBbXShzdGQ6OnN0cmluZyYgZHN0LCBhdXRvJiYgYXJnKSB7CiAgICBkc3QgKz0gYXJnOwogIH07CiAgCiAgKC4uLiwgY29uY2F0KHJldCwgY29udmVydChhcmdzKSkpOwogICAKICByZXR1cm4gcmV0Owp9CgppbnQgbWFpbigpCnsKICBzdGQ6OnN0cmluZyBoZWxsb3siaGVsbG8gIn07CiAgYXV0byBzID0gc3RyaW5naWZ5KCJBICIsIGhlbGxvLCAyLCAiICIsICJDKysgSW5zaWdodHMiKTsKCiAgcHJpbnRmKCIlc1xuIiwgcy5jX3N0cigpKTsKfQ==&amp;std=cpp17&amp;rev=1.0\">C++ Insights<\/a>. With all the templates, the code gets a little too big to show it here.<\/p>\n<p>I\u2019d like to mention one caveat at this point. The two lambdas <code>convert<\/code> and <code>concat<\/code> are generic lambdas. Internally they have a call operator which is a template. This is how we can have the auto parameter. Sadly, C++ Insights does not show this part yet. It\u2019s on the list and maybe fixed soon. I think it\u2019s worth knowing this.<\/p>\n<p>Amazing what we can do, right? I really like the way we can write code using the latest standard. I\u2019m also happy to offer you my training services to let you benefit from my knowledge.<\/p>\n<p>I\u2019d like to thank Rainer for the opportunity to share information about C++ Insights on his popular blog!<\/p>\n<p>Have fun with C++ Insights. You can support the project by becoming a <a href=\"https:\/\/www.patreon.com\/cppinsights\">Patreon<\/a> or of course with code <a href=\"https:\/\/github.com\/andreasfertig\/cppinsights\">contributions<\/a>.<\/p>\n<p>This is the last post of the series here. I hope you enjoyed reading it and took something from it. Now, its up to you to explore more about C++ Insights and the language itself.<\/p>\n<p><strong>I am Fertig.<\/strong><\/p>\n<p><strong>Andreas<\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Honestly, many programmers in my classes have issues with the syntactic sugar of lambdas. Desugaring lambdas with C++ Insights helps quite often.<\/p>\n","protected":false},"author":21,"featured_media":5660,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[374],"tags":[459],"class_list":["post-5661","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cppinsight","tag-lambdas"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5661","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=5661"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5661\/revisions"}],"predecessor-version":[{"id":6792,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5661\/revisions\/6792"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5660"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5661"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5661"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5661"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}