Something went wrong. Try again.
A Tour of C++ for experienced programmers, as if C++26 is the only version that ever existed.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507<!DOCTYPE HTML><html lang="en" class="light sidebar-visible" dir="ltr"> <head> <!-- Book generated using mdBook --> <meta charset="UTF-8"> <title>Reading the old magic: SFINAE, type_traits, and friends - A Tour of C++26</title>
<!-- Custom HTML head -->
<meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon-de23e50b.svg"> <link rel="shortcut icon" href="favicon-8114d1fc.png"> <link rel="stylesheet" href="css/variables-8adf115d.css"> <link rel="stylesheet" href="css/general-e96d0476.css"> <link rel="stylesheet" href="css/chrome-d279d366.css"> <link rel="stylesheet" href="css/print-9e4910d8.css" media="print">
<!-- Fonts --> <link rel="stylesheet" href="fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets --> <link rel="stylesheet" id="mdbook-highlight-css" href="highlight-493f70e1.css"> <link rel="stylesheet" id="mdbook-tomorrow-night-css" href="tomorrow-night-4c0ae647.css"> <link rel="stylesheet" id="mdbook-ayu-highlight-css" href="ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript --> <script> const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; window.path_to_searchindex_js = "searchindex-7c7963f3.js"; </script> <!-- Start loading toc.js asap --> <script src="toc-0eddcac6.js"></script> </head> <body> <div id="mdbook-help-container"> <div id="mdbook-help-popup"> <h2 class="mdbook-help-title">Keyboard shortcuts</h2> <div> <p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p> <p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p> <p>Press <kbd>?</kbd> to show this help</p> <p>Press <kbd>Esc</kbd> to hide this help</p> </div> </div> </div> <div id="mdbook-body-container"> <!-- Work around some values being stored in localStorage wrapped in quotes --> <script> try { let theme = localStorage.getItem('mdbook-theme'); let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) { localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); }
if (sidebar.startsWith('"') && sidebar.endsWith('"')) { localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); } } catch (e) { } </script>
<!-- Set the theme before any content is loaded, prevents flash --> <script> const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme; let theme; try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } if (theme === null || theme === undefined) { theme = default_theme; } const html = document.documentElement; html.classList.remove('light') html.classList.add(theme); html.classList.add("js"); </script>
<input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed --> <script> let sidebar = null; const sidebar_toggle = document.getElementById("mdbook-sidebar-toggle-anchor"); if (document.body.clientWidth >= 1080) { try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { } sidebar = sidebar || 'visible'; } else { sidebar = 'hidden'; sidebar_toggle.checked = false; } if (sidebar === 'visible') { sidebar_toggle.checked = true; } else { html.classList.remove('sidebar-visible'); } </script>
<nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents"> <!-- populated by js --> <mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox> <noscript> <iframe class="sidebar-iframe-outer" src="toc.html"></iframe> </noscript> <div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle"> <div class="sidebar-resize-indicator"></div> </div> </nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page"> <div id="mdbook-menu-bar-hover-placeholder"></div> <div id="mdbook-menu-bar" class="menu-bar sticky"> <div class="left-buttons"> <label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span> </label> <button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span> </button> <ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu"> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li> </ul> <button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span> </button> </div>
<h1 class="menu-title">A Tour of C++26</h1>
<div class="right-buttons"> <a href="print.html" title="Print this book" aria-label="Print this book"> <span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span> </a>
</div> </div>
<div id="mdbook-search-wrapper" class="hidden"> <form id="mdbook-searchbar-outer" class="searchbar-outer"> <div class="search-wrapper"> <input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header"> <div class="spinner-wrapper"> <span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span> </div> </div> </form> <div id="mdbook-searchresults-outer" class="searchresults-outer hidden"> <div id="mdbook-searchresults-header" class="searchresults-header"></div> <ul id="mdbook-searchresults"> </ul> </div> </div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM --> <script> document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible'); document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible'); Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) { link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1); }); </script>
<div id="mdbook-content" class="content"> <main> <h1 id="reading-the-old-magic-sfinae-type_traits-and-friends"><a class="header" href="#reading-the-old-magic-sfinae-type_traits-and-friends">Reading the old magic: SFINAE, type_traits, and friends</a></h1><h2 id="why-you-must-read-old-tmp"><a class="header" href="#why-you-must-read-old-tmp">Why you must read old TMP</a></h2><p>The C++ ecosystem did not jump from C++98 straight to concepts. Decades of libraries, such as the Standard Library, Boost, Eigen, and countless in-house frameworks, were written using SFINAE, <code>std::enable_if</code>, <code><type_traits></code> utilities, tag dispatch, and the Curiously Recurring Template Pattern (CRTP). When you encounter a templated overload that appears cryptic, you must not rewrite it immediately. First, decode the intent:</p><ol><li>Identify the <em>constraint</em> expressed by the enable-if or trait.</li><li>Translate that constraint into a <code>requires</code> clause or a named concept.</li><li>Verify that the modern form selects the same overload.</li></ol><p>This disciplined approach preserves the original algorithmic intent while allowing you to modernise gradually. Moreover, many code reviewers still expect you to read SFINAE-heavy code, because refactoring large libraries without breaking ABI is risky. By mastering the legacy patterns you become a bridge between the old and the new.</p><p>SFINAE and <code>enable_if</code> are not a separate language. They are template deduction rules pushed to their limits. Reading them as such, rather than as magic, makes the modern forms obvious. When you see <code>std::enable_if_t<...> = 0</code> in a signature, translate it in your head to the pre-concepts spelling of a <code>requires</code> clause, and the intent snaps into focus.</p><hr><h2 id="stdenable_if-positions"><a class="header" href="#stdenable_if-positions"><code>std::enable_if</code> positions</a></h2><p><code>std::enable_if</code> can appear in three classic locations:</p><ul><li><strong>Return type</strong>: the function’s result type is conditionally enabled.</li><li><strong>Default template parameter</strong>: the template parameter list carries a hidden <code>enable_if</code> that activates the overload.</li><li><strong>Parameter type</strong>: the function parameter itself is wrapped in <code>enable_if</code>, often for <code>std::string</code> arguments.</li></ul><p>Immediate-context rule: a substitution failure in the part of a declaration that participates in overload resolution removes the candidate without a diagnostic. This is the basis of SFINAE (Substitution Failure Is Not An Error). It lets <code>enable_if</code> expressions in return types, default template parameters, or parameter types silently disable overloads.</p><p>Below is a single file that demonstrates all three signatures. The program prints a message that identifies the selected overload. The modern rewrite, shown as comments, uses concepts to achieve the same overload resolution.</p><pre><code class="language-cpp">// ch21_enable_if_decode.cpp#include <iostream>#include <type_traits>#include <string>
// Overload using enable_if in return type (integral types)template <typename T>std::enable_if_t<std::is_integral_v<T>, std::string> foo(T) { std::cout << "int overload" << std::endl; return "int";}
// Overload using enable_if as a default template parameter (floating point types)template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>std::string foo(T) { std::cout << "float overload" << std::endl; return "float";}
// Overload using enable_if in a parameter type (std::string)template <typename T>std::enable_if_t<std::is_same_v<T, std::string>, std::string> foo(T const& value) { std::cout << "string overload" << std::endl; return value;}
int main() { foo(42); foo(3.14); foo(std::string{"hello"}); return 0;}</code></pre><pre><code class="language-cpp">// Modern rewrite (concept-based)template <typename T>requires std::integral<T>std::string foo(T) { std::cout << "int overload" << std::endl; return "int"; }
template <typename T>requires std::floating_point<T>std::string foo(T) { std::cout << "float overload" << std::endl; return "float"; }
template <typename T>requires std::same_as<T, std::string>std::string foo(T const& v) { std::cout << "string overload" << std::endl; return v; }</code></pre><p>Running the legacy example yields:</p><pre><code>int overloadfloat overloadstring overload</code></pre><p>Each overload is selected exactly as the concept-based version is, demonstrating a mechanical one-to-one mapping.</p><pre><code class="language-cpp">template <typename T, typename = std::void_t<decltype(std::declval<T>().size())>>void f(T const&) { std::cout << "has size" << std::endl; }
template <typename T>void f(T const&) { std::cout << "no size" << std::endl; }</code></pre><p>If <code>T</code> has a static member <code>size()</code>, the first overload is viable. Otherwise the substitution fails, the candidate is discarded, and the second overload wins. This behaviour underlies the <code>enable_if</code> patterns shown earlier. The <code>enable_if</code> expression lives in the immediate context, so a non-matching type eliminates the overload.</p><hr><h2 id="the-type_traits-vocabulary"><a class="header" href="#the-type_traits-vocabulary">The <code><type_traits></code> vocabulary</a></h2><p>The <code><type_traits></code> header provides a small declarative language that predates concepts. The most common utilities are:</p><ul><li><code>std::is_same_v<T,U></code>: true if <code>T</code> and <code>U</code> denote the same type.</li><li><code>std::is_integral_v<T></code>: true for integral types.</li><li><code>std::is_floating_point_v<T></code>: true for floating-point types.</li><li><code>std::conditional_t<C,T,F></code>: selects <code>T</code> if <code>C</code> is true, otherwise <code>F</code>.</li><li><code>std::void_t<...></code>: used to build detection idioms.</li></ul><p>The classic detection idiom uses <code>void_t</code> to test whether a particular expression is well-formed. The example below shows both the legacy and the modern approach.</p><pre><code class="language-cpp">// ch21_void_t_has_size.cpp#include <iostream>#include <type_traits>
// --- Classic detection using std::void_t ---struct WithSize { static constexpr std::size_t size() { return 5; }};struct WithoutSize {};
template <typename, typename = void>struct has_size : std::false_type {};
template <typename T>struct has_size<T, std::void_t<decltype(T::size())>> : std::true_type {};
// --- Modern detection using a requires expression (concept) ---template <typename T>concept HasSize = requires { T::size(); };
int main() { std::cout << "has_size<WithSize>::value = " << has_size<WithSize>::value << "\n"; std::cout << "has_size<WithoutSize>::value = " << has_size<WithoutSize>::value << "\n"; static_assert(HasSize<WithSize>, "WithSize satisfies HasSize"); static_assert(!HasSize<WithoutSize>, "WithoutSize does not satisfy HasSize"); return 0;}</code></pre><pre><code class="language-cpp">// Modern rewrite using a requires expression (concept)template <typename T>concept HasSize = requires { T::size(); };</code></pre><p>Both versions print the same truth values and compile-time <code>static_assert</code>s, confirming that the concept captures the exact same property as the <code>void_t</code> detector.</p><hr><h2 id="tag-dispatch"><a class="header" href="#tag-dispatch">Tag dispatch</a></h2><p>Tag dispatch separates overloads by passing an artificial <em>tag</em> type as an extra argument. The tag is selected by a <code>constexpr</code> function that examines type traits. The pattern is useful when you need a fast, binary-size friendly dispatch that does not rely on SFINAE.</p><pre><code class="language-cpp">// ch21_tag_dispatch.cpp#include <iostream>#include <type_traits>
// Tag typesstruct IntegralTag {};struct FloatingTag {};
// Primary overload – catches any type via tag dispatchtemplate <typename T>void print_type(T, IntegralTag) { std::cout << "integral" << std::endl;}
template <typename T>void print_type(T, FloatingTag) { std::cout << "floating" << std::endl;}
// Helper to select tag based on type traitstemplate <typename T>constexpr auto select_tag() { if constexpr (std::is_integral_v<T>) { return IntegralTag{}; } else if constexpr (std::is_floating_point_v<T>) { return FloatingTag{}; } else { static_assert(!std::is_same_v<T, T>, "Unsupported type"); }}
int main() { print_type(42, select_tag<int>()); print_type(3.14, select_tag<double>()); return 0;}</code></pre><p>The modern replacement uses <code>if constexpr</code> directly inside the function body, eliminating the need for separate tag types:</p><pre><code class="language-cpp">template <typename T>void print_type(T) { if constexpr (std::is_integral_v<T>) { std::cout << "integral" << std::endl; } else if constexpr (std::is_floating_point_v<T>) { std::cout << "floating" << std::endl; } else { static_assert(!std::is_same_v<T,T>, "Unsupported type"): }}</code></pre><p>Both implementations produce identical runtime output for the test cases. The tag types are cheap, because an empty struct carries no data and the compiler folds the dispatch away entirely, which is why the pattern remains common in performance-sensitive code.</p><hr><h2 id="crtp-curiously-recurring-template-pattern"><a class="header" href="#crtp-curiously-recurring-template-pattern">CRTP (Curiously Recurring Template Pattern)</a></h2><p>CRTP is a form of static polymorphism where a base class template takes the derived class as a parameter. The base can call functions that the derived implements. It uses <code>static_cast</code> to do so. This pattern appears in many older libraries (e.g., Boost.Fusion, Eigen) and remains useful for compile-time interfaces.</p><pre><code class="language-cpp">// ch21_crtp_shape.cpp#include <iostream>#include <type_traits>
// CRTP base that provides an interface for area()template <typename Derived>struct ShapeBase { // Calls the derived implementation via static_cast double area() const { return static_cast<const Derived*>(this)->area_impl(); }};
// Circle implementation using CRTPstruct Circle : ShapeBase<Circle> { double radius; explicit Circle(double r) : radius(r) {} double area_impl() const { return 3.1415926535 * radius * radius; }};
// Rectangle implementation using CRTPstruct Rectangle : ShapeBase<Rectangle> { double width, height; Rectangle(double w, double h) : width(w), height(h) {} double area_impl() const { return width * height; }};
int main() { Circle c(2.0); Rectangle r(3.0, 4.0); std::cout << "Circle area: " << c.area() << "\n"; std::cout << "Rectangle area: " << r.area() << "\n"; return 0;}</code></pre><p>A concept-based modern alternative expresses the same requirement with a <em>requires clause</em> on a free function or a generic algorithm, avoiding inheritance entirely:</p><pre><code class="language-cpp">template <typename Shape>concept ShapeLike = requires(const Shape& s) { s.area_impl(): }:
template <ShapeLike S>double area(const S& s) { return s.area_impl(): }</code></pre><p>The concept-based version provides the same static guarantee (<code>area_impl</code> exists) without the boilerplate of a CRTP base class.</p><p>The CRTP also lets a base provide default implementations that call into the derived type, which is how many mixin-style helpers share code without virtual dispatch. Because the call is resolved at compile time, it is inlined. This gives the performance of hand-written code with the reuse of a shared base.</p><hr><h2 id="translation-table"><a class="header" href="#translation-table">Translation table</a></h2><p>The following table summarises the mechanical rewrite from legacy constructs to their modern equivalents. Each row represents a direct replacement that preserves behaviour while simplifying the code.</p><div class="table-wrapper"><table><thead><tr><th>Legacy pattern</th><th>Modern equivalent</th></tr></thead><tbody><tr><td><code>std::enable_if</code> in return type, default template parameter, or parameter type</td><td><code>requires</code> clause or named concept</td></tr><tr><td>SFINAE (substitution failure)</td><td>Concept <em>subsumption</em> during overload resolution</td></tr><tr><td>Detection idiom with <code>std::void_t</code></td><td><code>requires { expr: }</code> (requires expression)</td></tr><tr><td>Tag dispatch (tag type + overload)</td><td><code>if constexpr</code> inside a single overload</td></tr><tr><td>CRTP static polymorphism</td><td>Concept-constrained free function or algorithm</td></tr></tbody></table></div><hr><h2 id="practical-migration-workflow"><a class="header" href="#practical-migration-workflow">Practical migration workflow</a></h2><p>When converting legacy TMP code, follow a systematic process. First, locate the overload set that uses <code>enable_if</code> or a detection idiom. Next, write an equivalent <code>requires</code> clause that captures the same logical condition. Then replace the multiple overloads with a single constrained function if possible. After editing, compile the program and verify that the output matches the original. Finally, run the book’s test harness to confirm that the <code>EXPECT</code> strings still pass.</p><p>Apply the same methodology to tag dispatch. Identify the tag types and the helper <code>select_tag</code> function. Replace them with an <code>if constexpr</code> chain that performs the same trait checks. Remove the tag definitions and the extra overloads. Compile and test to ensure identical behavior.</p><p>For CRTP bases, extract the required interface into a concept. Write free functions that operate on any type satisfying the concept. Remove the CRTP inheritance and replace it with calls to the free functions. Verify that the program still prints the expected results.</p><p>By iterating through each pattern in the translation table, you gradually modernize the codebase while maintaining functional parity. This approach reduces technical debt and improves readability for future maintainers.</p><h2 id="try-this"><a class="header" href="#try-this">Try this</a></h2><p>Translate the following three-overload <code>enable_if</code> set into a single concept-ordered function family. The original overloads handle (a) integral types, (b) floating-point types, and (c) all other types. After you rewrite, add a <code>static_assert</code> that verifies the same overload is selected for <code>int</code>, <code>double</code>, and <code>std::string</code>.</p><pre><code class="language-cpp">// Original legacy code (do not modify)template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>void process(T) { std::cout << "int" << std::endl; }
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, long> = 0>void process(T) { std::cout << "float" << std::endl; }
template <typename T, std::enable_if_t<!std::is_arithmetic_v<T>, void*> = nullptr>void process(T) { std::cout << "other" << std::endl; }</code></pre><p><em>Write the concept-based version and the <code>static_assert</code>s. No solution is provided.</em></p><hr><p>The translation of legacy patterns into concepts is not merely a stylistic upgrade: it has practical impacts on compilation speed, error diagnostics, and maintainability. Modern compilers can evaluate <code>requires</code> expressions early, pruning invalid overloads before template instantiation proceeds, which often reduces template recursion depth and improves compile-time feedback. Error messages tied to a concept name point directly at the violated constraint, a stark contrast to the often-cryptic cascade of errors produced by deep SFINAE failures.</p><p>Furthermore, concepts become part of the public interface. When a library author publishes a concept, downstream users can read the requirement in the function signature without hunting through implementation details. This self-documenting quality aligns with the book’s overarching philosophy: code must convey intent as clearly as possible.</p><p>When converting existing code, adopt a staged approach:</p><ol><li>Identify a SFINAE-enabled overload.</li><li>Write an equivalent <code>requires</code> clause, preserving the logical condition.</li><li>Replace the overload set with a single constrained function if possible.</li><li>Run the test suite to confirm behaviour remains identical.</li><li>Refactor additional legacy patterns (type-trait checks, tag dispatch, CRTP) following the same mechanical mapping.</li></ol><p>By iterating through the table above, you systematically reduce technical debt, modernise the codebase, and equip future contributors with clearer abstractions. The chapter’s examples demonstrate each step. They give you concrete, compile-tested references for every transformation.</p><p><em>The examples in this chapter are compiled and tested with the <code>book_example</code> macro. The <code>EXPECT</code> strings in the CMake registration verify that each program prints the expected identifiers.</em></p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation"> <!-- Mobile navigation buttons --> <a rel="prev" href="ch20-specialization.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span> </a>
<a rel="next prefetch" href="ch22-sql-capstone.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span> </a>
<div style="clear: both"></div> </nav> </div> </div>
<nav class="nav-wide-wrapper" aria-label="Page navigation"> <a rel="prev" href="ch20-specialization.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span> </a>
<a rel="next prefetch" href="ch22-sql-capstone.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span> </a> </nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template> <template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template> <template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template> <template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template> <template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<script> window.playground_copyable = true; </script>
<script src="elasticlunr-ef4e11c1.min.js"></script> <script src="mark-09e88c2c.min.js"></script> <script src="searcher-09f2665d.js"></script>
<script src="clipboard-1626706a.min.js"></script> <script src="highlight-abc7f01d.js"></script> <script src="book-609e4cb8.js"></script>
<!-- Custom JS scripts -->
</div> </body></html>