{"id":1376,"date":"2024-02-15T22:26:24","date_gmt":"2024-02-15T21:26:24","guid":{"rendered":"https:\/\/codevision.net.pl\/?p=1376"},"modified":"2024-02-15T22:26:26","modified_gmt":"2024-02-15T21:26:26","slug":"from-sfinae-to-concepts","status":"publish","type":"post","link":"https:\/\/codevision.net.pl\/index.php\/2024\/02\/15\/from-sfinae-to-concepts\/","title":{"rendered":"From SFINAE to Concepts"},"content":{"rendered":"\n<p>As software developers, our passion lies in harnessing the latest features of our favorite programming languages and frameworks. However, the harsh reality of daily work often imposes limitations, be it the environment, operating system, compiler, or underlying hardware. In the realm of long-term projects demanding continuous support and high stability, upgrading tools solely for the allure of fancy and modern features is not always a feasible option. The exception arises when critical weaknesses, safety concerns, or security issues necessitate an upgrade.<\/p>\n\n\n\n<p>The C++20 standard (ISO\/IEC 14882:2020(E) \u2013 Programming Language C++) brought forth several compelling features, including concepts, modules, and more. This is indeed great news for us, providing an opportunity to experiment with these advancements and potentially incorporate them into future commercial projects.<\/p>\n\n\n\n<p>Let&#8217;s delve into a simple template function designed to process any type of data:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\ntemplate &lt;typename T&gt;\nvoid process(T) {}\n<\/pre><\/div>\n\n\n<p>But what if we wish to narrow down this function to operate exclusively on integral types?<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\ntemplate &lt;typename T, typename = std::enable_if_t&lt;std::is_integral_v&lt;T&gt;&gt;&gt;\nvoid process(T) { \/* handles integral types only *\/ }\n<\/pre><\/div>\n\n\n<p>With the advent of C++20 concepts, we can introduce a more readable alternative:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\ntemplate &lt;typename T&gt;\nconcept Integral = std::is_integral_v&lt;T&gt;;\n\ntemplate &lt;Integral T&gt;\nvoid process(T) { \/* handles integral types only *\/ }\n<\/pre><\/div>\n\n\n<p>Moreover, we can define multiple concepts and leave a concept-less base template to handle any other types lacking a specific implementation:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\ntemplate &lt;typename T&gt;\nconcept Integral = std::is_integral_v&lt;T&gt;;\n\ntemplate &lt;typename T&gt;\nconcept Floating_point = std::is_floating_point_v&lt;T&gt;;\n\ntemplate &lt;Integral T&gt;\nvoid process(T) { \/* handles integral types only *\/ }\n\ntemplate &lt;Floating_point T&gt;\nvoid process(T) { \/* handles floating types only *\/}\n\ntemplate &lt;typename T&gt;\nvoid process(T) { \/* handles any other types *\/ }\n<\/pre><\/div>\n\n\n<p>While these examples are simplistic, envision the need to handle container-like iterable objects. Using SFINAE, we can implement a template function with such a limitation:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [29,30]; title: ; notranslate\" title=\"\">\ntemplate &lt;typename IterT, typename ContainerT&gt;\nusing Container_iterator = typename std::enable_if_t&lt;std::same_as&lt;IterT, typename ContainerT::iterator&gt; || std::same_as&lt;IterT, typename ContainerT::const_iterator&gt;&gt;;\n\ntemplate &lt;typename IterT, typename ContainerT, typename = void&gt;\nstruct is_container_iterator : std::false_type {};\n\ntemplate &lt;typename IterT, typename ContainerT&gt;\nstruct is_container_iterator&lt;IterT, ContainerT, Container_iterator&lt;IterT, ContainerT&gt;&gt; : std::true_type {};\n\ntemplate &lt;typename IterT, typename ContainerT&gt;\nconstexpr bool is_container_iterator_v = is_container_iterator&lt;IterT, ContainerT&gt;::value;\n\ntemplate &lt;typename T&gt;\nusing Container = typename std::enable_if_t&lt;is_container_iterator_v&lt;decltype(std::declval&lt;T &amp;&gt;().begin()), T&gt; &amp;&amp;\n                                            is_container_iterator_v&lt;decltype(std::declval&lt;T &amp;&gt;().end()), T&gt; &amp;&amp;\n                                            is_container_iterator_v&lt;decltype(std::declval&lt;T &amp;&gt;().cbegin()), T&gt; &amp;&amp;\n                                            is_container_iterator_v&lt;decltype(std::declval&lt;T &amp;&gt;().cend()), T&gt; &amp;&amp;\n                                            std::same_as&lt;decltype(std::declval&lt;T &amp;&gt;().size()), typename T::size_type&gt;&gt;;\n\ntemplate &lt;typename T, typename = void&gt;\nstruct is_container : std::false_type {};\n\ntemplate &lt;typename T&gt;\nstruct is_container&lt;T, Container&lt;T&gt;&gt; : std::true_type {};\n\ntemplate &lt;typename T&gt;\nconstexpr bool is_container_v = is_container&lt;T&gt;::value;\n\ntemplate &lt;typename T, typename = std::enable_if_t&lt;is_container_v&lt;T&gt;&gt;&gt;\nvoid process(T) { \/* handles container-like types *\/ }\n<\/pre><\/div>\n\n\n<p>Now, let&#8217;s reimagine the same functionality using concepts:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; highlight: [25,26]; title: ; notranslate\" title=\"\">\ntemplate &lt;typename IterT, typename ContainerT&gt;\nconcept Container_iterator =\n    std::same_as&lt;IterT, typename ContainerT::iterator&gt; ||\n    std::same_as&lt;IterT, typename ContainerT::const_iterator&gt;;\n\ntemplate &lt;typename T&gt;\nconcept Container = requires(T cont) {\n    {\n        cont.begin()\n    } -&gt; Container_iterator&lt;T&gt;;\n    {\n        cont.end()\n    } -&gt; Container_iterator&lt;T&gt;;\n    {\n        cont.cbegin()\n    } -&gt; Container_iterator&lt;T&gt;;\n    {\n        cont.cend()\n    } -&gt; Container_iterator&lt;T&gt;;\n    {\n        cont.size()\n    } -&gt; std::same_as&lt;typename T::size_type&gt;;\n};\n\ntemplate &lt;Container C&gt;\nvoid process(T) { \/* handles container-like types *\/ }\n<\/pre><\/div>\n\n\n<p>The difference is evident \u2013 concepts not only simplify the life of those implementing them but, more importantly, enhance the readability and maintainability of the code for those who come across it later.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As software developers, our passion lies in harnessing the latest features of our favorite programming languages and frameworks. However, the harsh reality of daily work often imposes limitations, be it the environment, operating system, compiler, or underlying hardware. In the realm of long-term projects demanding continuous support and high stability, upgrading tools solely for the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"zakra_sidebar_layout":"customizer","zakra_remove_content_margin":false,"zakra_sidebar":"customizer","zakra_transparent_header":"customizer","zakra_logo":0,"zakra_main_header_style":"default","zakra_menu_item_color":"","zakra_menu_item_hover_color":"","zakra_menu_item_active_color":"","zakra_menu_active_style":"","zakra_page_header":true,"_eb_attr":"","om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[17,16],"tags":[22,8,30,29,7],"class_list":["post-1376","post","type-post","status-publish","format-standard","hentry","category-c","category-development","tag-c-2","tag-development","tag-language","tag-programming","tag-software"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/codevision.net.pl\/index.php\/wp-json\/wp\/v2\/posts\/1376","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codevision.net.pl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codevision.net.pl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codevision.net.pl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codevision.net.pl\/index.php\/wp-json\/wp\/v2\/comments?post=1376"}],"version-history":[{"count":9,"href":"https:\/\/codevision.net.pl\/index.php\/wp-json\/wp\/v2\/posts\/1376\/revisions"}],"predecessor-version":[{"id":1386,"href":"https:\/\/codevision.net.pl\/index.php\/wp-json\/wp\/v2\/posts\/1376\/revisions\/1386"}],"wp:attachment":[{"href":"https:\/\/codevision.net.pl\/index.php\/wp-json\/wp\/v2\/media?parent=1376"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codevision.net.pl\/index.php\/wp-json\/wp\/v2\/categories?post=1376"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codevision.net.pl\/index.php\/wp-json\/wp\/v2\/tags?post=1376"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}