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.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456// Populate the sidebar//// This is a script, and not included directly in the page, to control the total size of the book.// The TOC contains an entry for each page, so if each page includes a copy of the TOC,// the total size of the page becomes O(n**2).class MDBookSidebarScrollbox extends HTMLElement { constructor() { super(); } connectedCallback() { this.innerHTML = '<ol class="chapter"><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="preface.html">Preface</a></span></li><li class="chapter-item expanded "><li class="part-title">Part I — The Language</li></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch01-toolchain.html"><strong aria-hidden="true">1.</strong> The compiler is a committee</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch02-values-functions.html"><strong aria-hidden="true">2.</strong> Values and functions</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch03-user-defined-types.html"><strong aria-hidden="true">3.</strong> User-defined types: structs, sums, and expectations</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch04-control-flow.html"><strong aria-hidden="true">4.</strong> Control flow, modernly</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch05-ownership-move-raii.html"><strong aria-hidden="true">5.</strong> Ownership, move, and RAII</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch06-smart-pointers.html"><strong aria-hidden="true">6.</strong> Smart pointers and owning views</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch07-lifetimes.html"><strong aria-hidden="true">7.</strong> Lifetimes, and the compiler that sees them</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch08-argument-passing.html"><strong aria-hidden="true">8.</strong> Passing arguments, returning values</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch09-errors-contracts.html"><strong aria-hidden="true">9.</strong> Errors: exceptions, expected, and contracts</a></span></li><li class="chapter-item expanded "><li class="part-title">Part II — The Standard Library</li></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch10-text.html"><strong aria-hidden="true">10.</strong> Text: strings, views, and formatting</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch11-containers.html"><strong aria-hidden="true">11.</strong> Containers</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch12-algorithms.html"><strong aria-hidden="true">12.</strong> Algorithms are the loops</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch13-ranges.html"><strong aria-hidden="true">13.</strong> Ranges and views</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch14-callables-type-erasure.html"><strong aria-hidden="true">14.</strong> Callables and type erasure</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch15-numerics.html"><strong aria-hidden="true">15.</strong> Numerics and multi-dimensional data</a></span></li><li class="chapter-item expanded "><li class="part-title">Part III — Generic and Compile-Time Programming</li></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch16-templates-functions.html"><strong aria-hidden="true">16.</strong> Templates I: functions that match</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch17-concepts.html"><strong aria-hidden="true">17.</strong> Concepts: the constraint language</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch18-compile-time.html"><strong aria-hidden="true">18.</strong> Compile-time C++</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch19-nttp.html"><strong aria-hidden="true">19.</strong> Values as template arguments</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch20-specialization.html"><strong aria-hidden="true">20.</strong> Specialization, overloading, customization points</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch21-legacy-tmp.html"><strong aria-hidden="true">21.</strong> Reading the old magic: SFINAE, type_traits, and friends</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch22-sql-capstone.html"><strong aria-hidden="true">22.</strong> Capstone: a constexpr SQL in C++26</a></span></li><li class="chapter-item expanded "><li class="part-title">Part IV — Systems</li></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch23-headers.html"><strong aria-hidden="true">23.</strong> Headers, #include, and organizing programs</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch24-modules.html"><strong aria-hidden="true">24.</strong> Modules, the standard's direction</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch25-concurrency-threads.html"><strong aria-hidden="true">25.</strong> Concurrency I: threads as values</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch26-concurrency-atomics.html"><strong aria-hidden="true">26.</strong> Concurrency II: atomics, and the shape of async</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch27-coroutines.html"><strong aria-hidden="true">27.</strong> Coroutines: suspension as first-class code</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch28-speaking-c.html"><strong aria-hidden="true">28.</strong> Speaking C</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="ch29-fast.html"><strong aria-hidden="true">29.</strong> Fast is a specification</a></span></li><li class="chapter-item expanded "><li class="part-title">Back matter</li></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="appendix-a.html"><strong aria-hidden="true">30.</strong> Appendix A: features and compilers</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="appendix-b.html"><strong aria-hidden="true">31.</strong> Appendix B: coming from other languages</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="appendix-c.html"><strong aria-hidden="true">32.</strong> Appendix C: Core Guidelines index</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="appendix-d.html"><strong aria-hidden="true">33.</strong> Appendix D: CMake</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="appendix-e.html"><strong aria-hidden="true">34.</strong> Appendix E: CTest</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="appendix-f.html"><strong aria-hidden="true">35.</strong> Appendix F: ASan and UBSan</a></span></li></ol>'; // Set the current, active page, and reveal it if it's hidden let current_page = document.location.href.toString().split('#')[0].split('?')[0]; if (current_page.endsWith('/')) { current_page += 'index.html'; } const links = Array.prototype.slice.call(this.querySelectorAll('a')); const l = links.length; for (let i = 0; i < l; ++i) { const link = links[i]; const href = link.getAttribute('href'); if (href && !href.startsWith('#') && !/^(?:[a-z+]+:)?\/\//.test(href)) { link.href = path_to_root + href; } // The 'index' page is supposed to alias the first chapter in the book. // Check both with and without the '.html' suffix to be robust against pretty URLs if (link.href.replace(/\.html$/, '') === current_page.replace(/\.html$/, '') || i === 0 && path_to_root === '' && current_page.endsWith('/index.html')) { link.classList.add('active'); let parent = link.parentElement; while (parent) { if (parent.tagName === 'LI' && parent.classList.contains('chapter-item')) { parent.classList.add('expanded'); } parent = parent.parentElement; } } } // Track and set sidebar scroll position this.addEventListener('click', e => { if (e.target.tagName === 'A') { const clientRect = e.target.getBoundingClientRect(); const sidebarRect = this.getBoundingClientRect(); sessionStorage.setItem('sidebar-scroll-offset', clientRect.top - sidebarRect.top); } }, { passive: true }); const sidebarScrollOffset = sessionStorage.getItem('sidebar-scroll-offset'); sessionStorage.removeItem('sidebar-scroll-offset'); if (sidebarScrollOffset !== null) { // preserve sidebar scroll position when navigating via links within sidebar const activeSection = this.querySelector('.active'); if (activeSection) { const clientRect = activeSection.getBoundingClientRect(); const sidebarRect = this.getBoundingClientRect(); const currentOffset = clientRect.top - sidebarRect.top; this.scrollTop += currentOffset - parseFloat(sidebarScrollOffset); } } else { // scroll sidebar to current active section when navigating via // 'next/previous chapter' buttons const activeSection = document.querySelector('#mdbook-sidebar .active'); if (activeSection) { activeSection.scrollIntoView({ block: 'center' }); } } // Toggle buttons const sidebarAnchorToggles = document.querySelectorAll('.chapter-fold-toggle'); function toggleSection(ev) { ev.currentTarget.parentElement.parentElement.classList.toggle('expanded'); } Array.from(sidebarAnchorToggles).forEach(el => { el.addEventListener('click', toggleSection); }); }}window.customElements.define('mdbook-sidebar-scrollbox', MDBookSidebarScrollbox);
// ---------------------------------------------------------------------------// Support for dynamically adding headers to the sidebar.
(function() { // This is used to detect which direction the page has scrolled since the // last scroll event. let lastKnownScrollPosition = 0; // This is the threshold in px from the top of the screen where it will // consider a header the "current" header when scrolling down. const defaultDownThreshold = 150; // Same as defaultDownThreshold, except when scrolling up. const defaultUpThreshold = 300; // The threshold is a virtual horizontal line on the screen where it // considers the "current" header to be above the line. The threshold is // modified dynamically to handle headers that are near the bottom of the // screen, and to slightly offset the behavior when scrolling up vs down. let threshold = defaultDownThreshold; // This is used to disable updates while scrolling. This is needed when // clicking the header in the sidebar, which triggers a scroll event. It // is somewhat finicky to detect when the scroll has finished, so this // uses a relatively dumb system of disabling scroll updates for a short // time after the click. let disableScroll = false; // Array of header elements on the page. let headers; // Array of li elements that are initially collapsed headers in the sidebar. // I'm not sure why eslint seems to have a false positive here. // eslint-disable-next-line prefer-const let headerToggles = []; // This is a debugging tool for the threshold which you can enable in the console. let thresholdDebug = false;
// Updates the threshold based on the scroll position. function updateThreshold() { const scrollTop = window.pageYOffset || document.documentElement.scrollTop; const windowHeight = window.innerHeight; const documentHeight = document.documentElement.scrollHeight;
// The number of pixels below the viewport, at most documentHeight. // This is used to push the threshold down to the bottom of the page // as the user scrolls towards the bottom. const pixelsBelow = Math.max(0, documentHeight - (scrollTop + windowHeight)); // The number of pixels above the viewport, at least defaultDownThreshold. // Similar to pixelsBelow, this is used to push the threshold back towards // the top when reaching the top of the page. const pixelsAbove = Math.max(0, defaultDownThreshold - scrollTop); // How much the threshold should be offset once it gets close to the // bottom of the page. const bottomAdd = Math.max(0, windowHeight - pixelsBelow - defaultDownThreshold); let adjustedBottomAdd = bottomAdd;
// Adjusts bottomAdd for a small document. The calculation above // assumes the document is at least twice the windowheight in size. If // it is less than that, then bottomAdd needs to be shrunk // proportional to the difference in size. if (documentHeight < windowHeight * 2) { const maxPixelsBelow = documentHeight - windowHeight; const t = 1 - pixelsBelow / Math.max(1, maxPixelsBelow); const clamp = Math.max(0, Math.min(1, t)); adjustedBottomAdd *= clamp; }
let scrollingDown = true; if (scrollTop < lastKnownScrollPosition) { scrollingDown = false; }
if (scrollingDown) { // When scrolling down, move the threshold up towards the default // downwards threshold position. If near the bottom of the page, // adjustedBottomAdd will offset the threshold towards the bottom // of the page. const amountScrolledDown = scrollTop - lastKnownScrollPosition; const adjustedDefault = defaultDownThreshold + adjustedBottomAdd; threshold = Math.max(adjustedDefault, threshold - amountScrolledDown); } else { // When scrolling up, move the threshold down towards the default // upwards threshold position. If near the bottom of the page, // quickly transition the threshold back up where it normally // belongs. const amountScrolledUp = lastKnownScrollPosition - scrollTop; const adjustedDefault = defaultUpThreshold - pixelsAbove + Math.max(0, adjustedBottomAdd - defaultDownThreshold); threshold = Math.min(adjustedDefault, threshold + amountScrolledUp); }
if (documentHeight <= windowHeight) { threshold = 0; }
if (thresholdDebug) { const id = 'mdbook-threshold-debug-data'; let data = document.getElementById(id); if (data === null) { data = document.createElement('div'); data.id = id; data.style.cssText = ` position: fixed; top: 50px; right: 10px; background-color: 0xeeeeee; z-index: 9999; pointer-events: none; `; document.body.appendChild(data); } data.innerHTML = ` <table> <tr><td>documentHeight</td><td>${documentHeight.toFixed(1)}</td></tr> <tr><td>windowHeight</td><td>${windowHeight.toFixed(1)}</td></tr> <tr><td>scrollTop</td><td>${scrollTop.toFixed(1)}</td></tr> <tr><td>pixelsAbove</td><td>${pixelsAbove.toFixed(1)}</td></tr> <tr><td>pixelsBelow</td><td>${pixelsBelow.toFixed(1)}</td></tr> <tr><td>bottomAdd</td><td>${bottomAdd.toFixed(1)}</td></tr> <tr><td>adjustedBottomAdd</td><td>${adjustedBottomAdd.toFixed(1)}</td></tr> <tr><td>scrollingDown</td><td>${scrollingDown}</td></tr> <tr><td>threshold</td><td>${threshold.toFixed(1)}</td></tr> </table> `; drawDebugLine(); }
lastKnownScrollPosition = scrollTop; }
function drawDebugLine() { if (!document.body) { return; } const id = 'mdbook-threshold-debug-line'; const existingLine = document.getElementById(id); if (existingLine) { existingLine.remove(); } const line = document.createElement('div'); line.id = id; line.style.cssText = ` position: fixed; top: ${threshold}px; left: 0; width: 100vw; height: 2px; background-color: red; z-index: 9999; pointer-events: none; `; document.body.appendChild(line); }
function mdbookEnableThresholdDebug() { thresholdDebug = true; updateThreshold(); drawDebugLine(); }
window.mdbookEnableThresholdDebug = mdbookEnableThresholdDebug;
// Updates which headers in the sidebar should be expanded. If the current // header is inside a collapsed group, then it, and all its parents should // be expanded. function updateHeaderExpanded(currentA) { // Add expanded to all header-item li ancestors. let current = currentA.parentElement; while (current) { if (current.tagName === 'LI' && current.classList.contains('header-item')) { current.classList.add('expanded'); } current = current.parentElement; } }
// Updates which header is marked as the "current" header in the sidebar. // This is done with a virtual Y threshold, where headers at or below // that line will be considered the current one. function updateCurrentHeader() { if (!headers || !headers.length) { return; }
// Reset the classes, which will be rebuilt below. const els = document.getElementsByClassName('current-header'); for (const el of els) { el.classList.remove('current-header'); } for (const toggle of headerToggles) { toggle.classList.remove('expanded'); }
// Find the last header that is above the threshold. let lastHeader = null; for (const header of headers) { const rect = header.getBoundingClientRect(); if (rect.top <= threshold) { lastHeader = header; } else { break; } } if (lastHeader === null) { lastHeader = headers[0]; const rect = lastHeader.getBoundingClientRect(); const windowHeight = window.innerHeight; if (rect.top >= windowHeight) { return; } }
// Get the anchor in the summary. const href = '#' + lastHeader.id; const a = [...document.querySelectorAll('.header-in-summary')] .find(element => element.getAttribute('href') === href); if (!a) { return; }
a.classList.add('current-header');
updateHeaderExpanded(a); }
// Updates which header is "current" based on the threshold line. function reloadCurrentHeader() { if (disableScroll) { return; } updateThreshold(); updateCurrentHeader(); }
// When clicking on a header in the sidebar, this adjusts the threshold so // that it is located next to the header. This is so that header becomes // "current". function headerThresholdClick(event) { // See disableScroll description why this is done. disableScroll = true; setTimeout(() => { disableScroll = false; }, 100); // requestAnimationFrame is used to delay the update of the "current" // header until after the scroll is done, and the header is in the new // position. requestAnimationFrame(() => { requestAnimationFrame(() => { // Closest is needed because if it has child elements like <code>. const a = event.target.closest('a'); const href = a.getAttribute('href'); const targetId = href.substring(1); const targetElement = document.getElementById(targetId); if (targetElement) { threshold = targetElement.getBoundingClientRect().bottom; updateCurrentHeader(); } }); }); }
// Takes the nodes from the given head and copies them over to the // destination, along with some filtering. function filterHeader(source, dest) { const clone = source.cloneNode(true); clone.querySelectorAll('mark').forEach(mark => { mark.replaceWith(...mark.childNodes); }); dest.append(...clone.childNodes); }
// Scans page for headers and adds them to the sidebar. document.addEventListener('DOMContentLoaded', function() { const activeSection = document.querySelector('#mdbook-sidebar .active'); if (activeSection === null) { return; }
const main = document.getElementsByTagName('main')[0]; headers = Array.from(main.querySelectorAll('h2, h3, h4, h5, h6')) .filter(h => h.id !== '' && h.children.length && h.children[0].tagName === 'A');
if (headers.length === 0) { return; }
// Build a tree of headers in the sidebar.
const stack = [];
const firstLevel = parseInt(headers[0].tagName.charAt(1)); for (let i = 1; i < firstLevel; i++) { const ol = document.createElement('ol'); ol.classList.add('section'); if (stack.length > 0) { stack[stack.length - 1].ol.appendChild(ol); } stack.push({level: i + 1, ol: ol}); }
// The level where it will start folding deeply nested headers. const foldLevel = 3;
for (let i = 0; i < headers.length; i++) { const header = headers[i]; const level = parseInt(header.tagName.charAt(1));
const currentLevel = stack[stack.length - 1].level; if (level > currentLevel) { // Begin nesting to this level. for (let nextLevel = currentLevel + 1; nextLevel <= level; nextLevel++) { const ol = document.createElement('ol'); ol.classList.add('section'); const last = stack[stack.length - 1]; const lastChild = last.ol.lastChild; // Handle the case where jumping more than one nesting // level, which doesn't have a list item to place this new // list inside of. if (lastChild) { lastChild.appendChild(ol); } else { last.ol.appendChild(ol); } stack.push({level: nextLevel, ol: ol}); } } else if (level < currentLevel) { while (stack.length > 1 && stack[stack.length - 1].level > level) { stack.pop(); } }
const li = document.createElement('li'); li.classList.add('header-item'); li.classList.add('expanded'); if (level < foldLevel) { li.classList.add('expanded'); } const span = document.createElement('span'); span.classList.add('chapter-link-wrapper'); const a = document.createElement('a'); span.appendChild(a); a.href = '#' + header.id; a.classList.add('header-in-summary'); filterHeader(header.children[0], a); a.addEventListener('click', headerThresholdClick); const nextHeader = headers[i + 1]; if (nextHeader !== undefined) { const nextLevel = parseInt(nextHeader.tagName.charAt(1)); if (nextLevel > level && level >= foldLevel) { const toggle = document.createElement('a'); toggle.classList.add('chapter-fold-toggle'); toggle.classList.add('header-toggle'); toggle.addEventListener('click', () => { li.classList.toggle('expanded'); }); const toggleDiv = document.createElement('div'); toggleDiv.textContent = '❱'; toggle.appendChild(toggleDiv); span.appendChild(toggle); headerToggles.push(li); } } li.appendChild(span);
const currentParent = stack[stack.length - 1]; currentParent.ol.appendChild(li); }
const onThisPage = document.createElement('div'); onThisPage.classList.add('on-this-page'); onThisPage.append(stack[0].ol); const activeItemSpan = activeSection.parentElement; activeItemSpan.after(onThisPage); });
document.addEventListener('DOMContentLoaded', reloadCurrentHeader); document.addEventListener('scroll', reloadCurrentHeader, { passive: true });})();