{"id":5821,"date":"2019-12-06T07:11:00","date_gmt":"2019-12-06T07:11:00","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-20-concepts-the-placeholder-syntax\/"},"modified":"2023-06-26T09:57:04","modified_gmt":"2023-06-26T09:57:04","slug":"c-20-concepts-the-placeholder-syntax","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-20-concepts-the-placeholder-syntax\/","title":{"rendered":"C++20: Concepts, the Placeholder Syntax"},"content":{"rendered":"<p>Today, I have a simple answer to a challenging question: Where can I use my concept? Concepts can be used where <span style=\"font-family: courier new, courier;\">auto<\/span> is usable.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5808\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/11\/TimelineCpp20Concepts.png\" alt=\"TimelineCpp20Concepts\" width=\"600\" height=\"235\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/11\/TimelineCpp20Concepts.png 954w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/11\/TimelineCpp20Concepts-300x118.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/11\/TimelineCpp20Concepts-768x301.png 768w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>Before I write about the placeholder syntax and the new way to define function templates, I must make a detour. We have asymmetries in C++11\/14.<\/p>\n<h2>From Asymmetries in C++11\/14 to Symmetries in C++20<\/h2>\n<p>I often have discussions in my C++ seminars that goes like this.<\/p>\n<p>What is the Standard Template Library from the birds-eyes perspective? Generic containers can be manipulated with generic algorithms. The glue between these two disjunct components is iterators.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5818\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/12\/stl.png\" alt=\"stl\" width=\"400\" height=\"103\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/12\/stl.png 882w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/12\/stl-300x77.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/12\/stl-768x198.png 768w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>Generic containers and algorithms mean they are not bound to a specific type. Fine. Many of the algorithms can be parametrized by a callable. For example, <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/algorithm\/sort\"><span style=\"font-family: courier new, courier;\">std::sort<\/span><\/a> has an overload that takes a binary predicate (callable). This binary predicate is applied to the elements of the container. A binary predicate is a function that takes two arguments and returns a boolean. You can use a function, a function object, or with C++11 lambda as a binary predicate.<\/p>\n<h3>The Small Asymmetry in C++11<\/h3>\n<p>What&#8217;s wrong with the following program? (I know that we have<span style=\"font-family: courier new, courier;\"> <\/span>the predefined predicate <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/functional\/greater\">std::greater<\/a>.)<\/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: #0099ff; font-style: italic;\">\/\/ lambdaCpp11.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;algorithm&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;array&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;vector&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: #006699; font-weight: bold;\">typename<\/span> Pred<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> sortDescending(Cont<span style=\"color: #555555;\">&amp;<\/span> cont, Pred pred){\r\n    std<span style=\"color: #555555;\">::<\/span>sort(cont.begin(), cont.end(), pred);\r\n}\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> printMe(<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;\">auto<\/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> std<span style=\"color: #555555;\">::<\/span>endl;\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>array<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span>, <span style=\"color: #ff6600;\">10<\/span><span style=\"color: #555555;\">&gt;<\/span> myArray{<span style=\"color: #ff6600;\">5<\/span>, <span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">10<\/span>, <span style=\"color: #ff6600;\">3<\/span>, <span style=\"color: #ff6600;\">2<\/span>, <span style=\"color: #ff6600;\">7<\/span>, <span style=\"color: #ff6600;\">8<\/span>, <span style=\"color: #ff6600;\">9<\/span>, <span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">4<\/span>, <span style=\"color: #ff6600;\">3<\/span>, <span style=\"color: #ff6600;\">4<\/span>};\r\n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">double<\/span><span style=\"color: #555555;\">&gt;<\/span> myVector{<span style=\"color: #ff6600;\">5.1<\/span>, <span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">10.5<\/span>, <span style=\"color: #ff6600;\">3.1<\/span>, <span style=\"color: #ff6600;\">2.0<\/span>, <span style=\"color: #ff6600;\">7.2<\/span>, <span style=\"color: #ff6600;\">8.3<\/span>};\r\n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>string<span style=\"color: #555555;\">&gt;<\/span> myVector2{<span style=\"color: #cc3300;\">\"Only\"<\/span>, <span style=\"color: #cc3300;\">\"for\"<\/span>, <span style=\"color: #cc3300;\">\"testing\"<\/span>, <span style=\"color: #cc3300;\">\"purpose\"<\/span>};\r\n    \r\n    sortDescending(myArray, [](<span style=\"color: #007788; font-weight: bold;\">int<\/span> fir, <span style=\"color: #007788; font-weight: bold;\">int<\/span> sec){ <span style=\"color: #006699; font-weight: bold;\">return<\/span> fir <span style=\"color: #555555;\">&gt;<\/span> sec; });           <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n    sortDescending(myVector, [](<span style=\"color: #007788; font-weight: bold;\">double<\/span> fir, <span style=\"color: #007788; font-weight: bold;\">double<\/span> sec){ <span style=\"color: #006699; font-weight: bold;\">return<\/span> fir <span style=\"color: #555555;\">&gt;<\/span> sec; });    <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n    sortDescending(myVector2, [](<span style=\"color: #006699; font-weight: bold;\">const<\/span> std<span style=\"color: #555555;\">::<\/span>string<span style=\"color: #555555;\">&amp;<\/span> fir, <span style=\"color: #006699; font-weight: bold;\">const<\/span> std<span style=\"color: #555555;\">::<\/span>string<span style=\"color: #555555;\">&amp;<\/span> sec){ <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n       <span style=\"color: #006699; font-weight: bold;\">return<\/span> fir <span style=\"color: #555555;\">&gt;<\/span> sec; \r\n    });\r\n\r\n    printMe(myArray);\r\n    printMe(myVector);\r\n    printMe(myVector2);\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 program has a <span style=\"font-family: courier new, courier;\">std::array<\/span> of <span style=\"font-family: courier new, courier;\">int&#8217;<\/span>s, a <span style=\"font-family: courier new, courier;\">std::vector<\/span> of <span style=\"font-family: courier new, courier;\">double&#8217;<\/span>s, and a <span style=\"font-family: courier new, courier;\">std::vector<\/span> of <span style=\"font-family: courier new, courier;\">std::string<\/span>&#8216;s. All containers should be sorted in descending order and displayed. To ease my job, I create the two function templates <span style=\"font-family: courier new, courier;\">sortDescending<\/span> and <span style=\"font-family: courier new, courier;\">printMe. <\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5819\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/12\/lambdaCpp11.png\" alt=\"lambdaCpp11\" width=\"300\" height=\"191\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/12\/lambdaCpp11.png 369w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/12\/lambdaCpp11-300x191.png 300w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>Although containers and algorithms are generic, C++11 has only type-based lambdas. I have to implement the binary predicate for each data type (lines 1 &#8211; 3) and break, therefore, my generic approach.<\/p>\n<p>With C++14, this asymmetry disappears. Containers and algorithms are generic, and lambdas can be generic.<\/p>\n<\/p>\n<h3>The Big Asymmetry in C++14<\/h3>\n<p>C++14 implements the previous program <span style=\"font-family: courier new, courier;\">lambdaCpp11.cpp<\/span> straightforward.<\/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: #0099ff; font-style: italic;\">\/\/ lambdaCpp14.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;algorithm&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;array&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;vector&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> sortDescending(Cont<span style=\"color: #555555;\">&amp;<\/span> cont){\r\n    std<span style=\"color: #555555;\">::<\/span>sort(cont.begin(), cont.end(), [](<span style=\"color: #006699; font-weight: bold;\">auto<\/span> fir, <span style=\"color: #006699; font-weight: bold;\">auto<\/span> sec){   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> fir <span style=\"color: #555555;\">&gt;<\/span> sec; \r\n    });\r\n}\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> printMe(<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;\">auto<\/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> std<span style=\"color: #555555;\">::<\/span>endl;\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>array<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span>, <span style=\"color: #ff6600;\">10<\/span><span style=\"color: #555555;\">&gt;<\/span> myArray{<span style=\"color: #ff6600;\">5<\/span>, <span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">10<\/span>, <span style=\"color: #ff6600;\">3<\/span>, <span style=\"color: #ff6600;\">2<\/span>, <span style=\"color: #ff6600;\">7<\/span>, <span style=\"color: #ff6600;\">8<\/span>, <span style=\"color: #ff6600;\">9<\/span>, <span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">4<\/span>, <span style=\"color: #ff6600;\">3<\/span>, <span style=\"color: #ff6600;\">4<\/span>};\r\n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">double<\/span><span style=\"color: #555555;\">&gt;<\/span> myVector{<span style=\"color: #ff6600;\">5.1<\/span>, <span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">10.5<\/span>, <span style=\"color: #ff6600;\">3.1<\/span>, <span style=\"color: #ff6600;\">2.0<\/span>, <span style=\"color: #ff6600;\">7.2<\/span>, <span style=\"color: #ff6600;\">8.3<\/span>};\r\n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>string<span style=\"color: #555555;\">&gt;<\/span> myVector2{<span style=\"color: #cc3300;\">\"Only\"<\/span>, <span style=\"color: #cc3300;\">\"for\"<\/span>, <span style=\"color: #cc3300;\">\"testing\"<\/span>, <span style=\"color: #cc3300;\">\"purpose\"<\/span>};\r\n    \r\n    sortDescending(myArray);      <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n    sortDescending(myVector);     <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n    sortDescending(myVector2);    <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n\r\n    printMe(myArray);\r\n    printMe(myVector);\r\n    printMe(myVector2);\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><span style=\"font-family: courier new, courier;\"><\/span><\/p>\n<p>Fine? Yes and No. Yes, because I can use a generic lambda (line 1) for each data type in line 2. No, because I replaced one slight asymmetry in C++11 with a bigger asymmetry in C++14. The slight asymmetry in C++11 was that a lambda is type-bound. The big asymmetry in C++14 is that generic lambda introduced a new syntactic form to write generic functions, better known as function templates. Here is the proof:<\/p>\n<p>&nbsp;<\/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: #0099ff; font-style: italic;\">\/\/ genericLambdaTemplate.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;\">auto<\/span> addLambda <span style=\"color: #555555;\">=<\/span> [](<span style=\"color: #006699; font-weight: bold;\">auto<\/span> fir, <span style=\"color: #006699; font-weight: bold;\">auto<\/span> sec){ <span style=\"color: #006699; font-weight: bold;\">return<\/span> fir <span style=\"color: #555555;\">+<\/span> sec; }; <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/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> T, <span style=\"color: #006699; font-weight: bold;\">typename<\/span> T2<span style=\"color: #555555;\">&gt;<\/span>                            <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n<span style=\"color: #006699; font-weight: bold;\">auto<\/span> addTemplate(T fir, T2 sec){ <span style=\"color: #006699; font-weight: bold;\">return<\/span> fir <span style=\"color: #555555;\">+<\/span> sec; }\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>boolalpha <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> addLambda(<span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> addTemplate(<span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> addLambda(<span style=\"color: #336666;\">true<\/span>, <span style=\"color: #ff6600;\">5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> addTemplate(<span style=\"color: #336666;\">true<\/span>, <span style=\"color: #ff6600;\">5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> addLambda(<span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">5.5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> addTemplate(<span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">5.5<\/span>) <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;\">const<\/span> std<span style=\"color: #555555;\">::<\/span>string fir{<span style=\"color: #cc3300;\">\"ge\"<\/span>};\r\n    <span style=\"color: #006699; font-weight: bold;\">const<\/span> std<span style=\"color: #555555;\">::<\/span>string sec{<span style=\"color: #cc3300;\">\"neric\"<\/span>};\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> addLambda(fir, sec) <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> addTemplate(fir, sec) <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>The generic lambda in line 1 and the function template in line 2 produce the same results.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5820\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/12\/genericLambdaTemplate.png\" alt=\"genericLambdaTemplate\" width=\"350\" height=\"218\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/12\/genericLambdaTemplate.png 425w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/12\/genericLambdaTemplate-300x187.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<p>This is the asymmetry in C++14. Generic lambdas introduce a new way to define function templates.<\/p>\n<p>When I teach this in my seminars, I almost always get the question: Can we use <span style=\"font-family: courier new, courier;\">auto<\/span> in functions to get function templates? No with C++17, but yes with C++20.&nbsp; In C++20, you can use constrained placeholders (concepts) or unconstrained placeholders <span style=\"font-family: courier new, courier;\">(auto)<\/span> in function declarations to get function templates. This means the asymmetry in C++ is gone with C++20.<\/p>\n<h3>The Solution in C++20<\/h3>\n<p>Before I write about the new definition of function templates, I want to answer my original question: Where can I use my concept? Concepts can be used where <span style=\"font-family: courier new, courier;\">auto<\/span> is usable.<\/p>\n<p>&nbsp;<\/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: #0099ff; font-style: italic;\">\/\/ placeholdersDraft.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;type_traits&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;vector&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> T<span style=\"color: #555555;\">&gt;<\/span>                                   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\nconcept Integral <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>is_integral<span style=\"color: #555555;\">&lt;<\/span>T<span style=\"color: #555555;\">&gt;::<\/span>value;\r\n\r\nIntegral <span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #cc00ff;\">getIntegral<\/span>(<span style=\"color: #007788; font-weight: bold;\">int<\/span> val){                    <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> val;\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>boolalpha <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n \r\n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> vec{<span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">2<\/span>, <span style=\"color: #ff6600;\">3<\/span>, <span style=\"color: #ff6600;\">4<\/span>, <span style=\"color: #ff6600;\">5<\/span>};\r\n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (Integral <span style=\"color: #006699; font-weight: bold;\">auto<\/span> i<span style=\"color: #555555;\">:<\/span> vec) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> i <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" \"<\/span>;  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n \r\n    Integral <span style=\"color: #006699; font-weight: bold;\">auto<\/span> b <span style=\"color: #555555;\">=<\/span> <span style=\"color: #336666;\">true<\/span>;                            <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> b <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n\r\n    Integral <span style=\"color: #006699; font-weight: bold;\">auto<\/span> integ <span style=\"color: #555555;\">=<\/span> getIntegral(<span style=\"color: #ff6600;\">10<\/span>);             <span style=\"color: #0099ff; font-style: italic;\">\/\/ (5)<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> integ <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> integ1 <span style=\"color: #555555;\">=<\/span> getIntegral(<span style=\"color: #ff6600;\">10<\/span>);                     <span style=\"color: #0099ff; font-style: italic;\">\/\/ (6)<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> integ1 <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>The concept <span style=\"font-family: courier new, courier;\">Integral<\/span> in line 1 can be used as a return type (line 2), in a range-based for-loop (line 3), or as a type for the variable <span style=\"font-family: courier new, courier;\">b<\/span> (line 4) or the variable <span style=\"font-family: courier new, courier;\">integ <\/span>(line 5). To see the symmetry, line 6 uses type-deduction with <span style=\"font-family: courier new, courier;\">auto<\/span> instead. I have to admit that no compiler is now available to compile the proposed concepts syntax I used in my example. The following output is, therefore, from GCC and the previous Concepts Technical Specification (Concepts TS).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5212\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/03\/conceptsPlaceholder.png\" alt=\"conceptsPlaceholder\" width=\"350\" height=\"179\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/03\/conceptsPlaceholder.png 379w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/03\/conceptsPlaceholder-300x154.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>My<a href=\"https:\/\/www.modernescpp.com\/index.php\/brief-overview-of-the-pvs-studio-static-code-analyzer\"> next post <\/a>concerns the syntactic sugar we get with constrained placeholders (concepts) and unconstrained placeholders (auto) in C++20. I assume the function (template)<span style=\"font-family: courier new, courier;\"> getIntegral<\/span> gives you a first impression.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today, I have a simple answer to a challenging question: Where can I use my concept? Concepts can be used where auto is usable.<\/p>\n","protected":false},"author":21,"featured_media":5808,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[415],"class_list":["post-5821","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-concepts"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5821","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=5821"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5821\/revisions"}],"predecessor-version":[{"id":6763,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5821\/revisions\/6763"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5808"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5821"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5821"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5821"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}