C++ Stories https://www.cppstories.com/ Recent content on C++ Stories Hugo -- gohugo.io en-us Sat, 14 Feb 2026 00:00:00 +0000 Understanding std::shared_mutex from C++17 https://www.cppstories.com/2026/shared_mutex/ Sat, 14 Feb 2026 00:00:00 +0000 https://www.cppstories.com/2026/shared_mutex/ <p>In this article, we’ll start with a basic example using <code>std::mutex</code>, look at its limitations, and then introduce <code>std::shared_mutex</code>, a reader-writer mutex added in C++17. Even in 2026, with many new concurrency features available, <code>std::shared_mutex</code> is still a valuable and practical tool.</p> <p>Let’s jump in.</p> <h2 id="a-simple-thread-safe-counter-with-stdmutex"> A Simple Thread-Safe Counter with <code>std::mutex</code> <a class="hash-link" href="#a-simple-thread-safe-counter-with-stdmutex" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>We’ll begin with a small example (a standard &ldquo;hello world&rdquo; for this type of mutexes): a counter object that multiple threads can access:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;mutex&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Counter</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">get</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">lock_guard</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">mutex</span><span class="o">&gt;</span> <span class="n">lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">value_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">increment</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">lock_guard</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">mutex</span><span class="o">&gt;</span> <span class="n">lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="o">++</span><span class="n">value_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">mutable</span> <span class="n">std</span><span class="o">::</span><span class="n">mutex</span> <span class="n">mutex_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">value_</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span></code></pre></div><p>Nothing scary so far, and this implementation is correct, thread-safe, and easy to understand.</p> <p>However, there’s a significant limitation: All access is exclusive.</p> <p>Only one thread can call <code>get()</code> or <code>increment()</code> at any given time, even though <code>get()</code> does not modify the state.</p> <h2 id="when-stdmutex-becomes-a-bottleneck"> When <code>std::mutex</code> Becomes a Bottleneck <a class="hash-link" href="#when-stdmutex-becomes-a-bottleneck" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In many real-world programs, shared data is read frequently and might be rarely updated/overriden.</p> <p>For example:</p> <ul> <li>configuration data</li> <li>caches</li> <li>lookup tables</li> <li>statistics and metrics</li> </ul> <p>With <code>std::mutex</code>, even multiple read-only operations block each other. This limits scalability and wastes available parallelism.</p> <p>Have a look at the following example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Counter</span> <span class="n">counter</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">jthread</span><span class="o">&gt;</span> <span class="n">threads</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">threads</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">([</span><span class="o">&amp;</span><span class="n">counter</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">counter</span><span class="p">.</span><span class="n">increment</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep_for</span><span class="p">(</span><span class="mi">15</span><span class="n">ms</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">threads</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">([</span><span class="o">&amp;</span><span class="n">counter</span><span class="p">,</span> <span class="n">i</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;reader {} sees {}&#34;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">counter</span><span class="p">.</span><span class="n">get</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep_for</span><span class="p">(</span><span class="mi">10</span><span class="n">ms</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>On Compiler Explorer - see here <a href="https://godbolt.org/z/cdjrj8hGd">https://godbolt.org/z/cdjrj8hGd</a> - I&rsquo;m getting the following output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Program returned: 0 </span></span><span class="line"><span class="cl">reader 0 sees 0 </span></span><span class="line"><span class="cl">reader 1 sees 1 </span></span><span class="line"><span class="cl">reader 2 sees 1 </span></span><span class="line"><span class="cl">reader 3 sees 1 </span></span><span class="line"><span class="cl">reader 0 sees 1 </span></span><span class="line"><span class="cl">reader 1 sees 1 </span></span><span class="line"><span class="cl">reader 2 sees 1 </span></span><span class="line"><span class="cl">reader 3 sees 1 </span></span><span class="line"><span class="cl">reader 2 sees 2 </span></span><span class="line"><span class="cl">reader 3 sees 2 </span></span><span class="line"><span class="cl">reader 0 sees 2 </span></span><span class="line"><span class="cl">reader 1 sees 2 </span></span><span class="line"><span class="cl">reader 0 sees 3 </span></span><span class="line"><span class="cl">reader 1 sees 3 </span></span><span class="line"><span class="cl">reader 2 sees 3 </span></span><span class="line"><span class="cl">reader 3 sees 3 </span></span><span class="line"><span class="cl">reader 3 sees 3 </span></span><span class="line"><span class="cl">reader 0 sees 3 </span></span><span class="line"><span class="cl">reader 1 sees 3 </span></span><span class="line"><span class="cl">reader 2 sees 3 </span></span><span class="line"><span class="cl">reader 3 sees 4 </span></span><span class="line"><span class="cl">reader 1 sees 4 </span></span><span class="line"><span class="cl">reader 2 sees 4 </span></span><span class="line"><span class="cl">reader 0 sees 4 </span></span><span class="line"><span class="cl">reader 3 sees 5 </span></span><span class="line"><span class="cl">reader 1 sees 5 </span></span><span class="line"><span class="cl">reader 2 sees 5 </span></span><span class="line"><span class="cl">reader 0 sees 5 </span></span><span class="line"><span class="cl">reader 1 sees 5 </span></span><span class="line"><span class="cl">reader 2 sees 5 </span></span><span class="line"><span class="cl">reader 3 sees 5 </span></span><span class="line"><span class="cl">reader 0 sees 5 </span></span><span class="line"><span class="cl">reader 2 sees 6 </span></span><span class="line"><span class="cl">reader 3 sees 6 </span></span><span class="line"><span class="cl">reader 0 sees 6 </span></span><span class="line"><span class="cl">reader 1 sees 6 </span></span><span class="line"><span class="cl">reader 3 sees 7 </span></span><span class="line"><span class="cl">reader 0 sees 7 </span></span><span class="line"><span class="cl">reader 2 sees 7 </span></span><span class="line"><span class="cl">reader 1 sees 7 </span></span></code></pre></div><p>Notice that some lines repeat the same value. That’s expected. The writer increments the counter every ~15 ms, but readers sample it every ~10 ms, so they can observe the same value more than once. Also, thread scheduling is not deterministic, so each reader may see a slightly different sequence.</p> <p>In the demo code, there are many more reads than writes, so is the <code>mutex</code> the best solution here?</p> <h2 id="introducing-stdshared_mutex"> Introducing <code>std::shared_mutex</code> <a class="hash-link" href="#introducing-stdshared_mutex" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><code>std::shared_mutex</code> is a reader-writer mutex. It supports two locking modes:</p> <ul> <li>shared ownership - many threads can hold the lock simultaneously</li> <li>exclusive ownership - only one thread can hold the lock</li> </ul> <p>This makes <code>std::shared_mutex</code> a good fit for read-mostly data structures.</p> <h2 id="refactoring-the-counter-with-stdshared_mutex"> Refactoring the Counter with <code>std::shared_mutex</code> <a class="hash-link" href="#refactoring-the-counter-with-stdshared_mutex" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Let’s update the counter example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;shared_mutex&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;mutex&gt; // for locks</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Counter</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">get</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">shared_lock</span> <span class="n">lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">value_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">increment</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">unique_lock</span> <span class="n">lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="o">++</span><span class="n">value_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">mutable</span> <span class="n">std</span><span class="o">::</span><span class="n">shared_mutex</span> <span class="n">mutex_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">value_</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span></code></pre></div><p>What changed?</p> <ul> <li><code>get()</code> now uses <code>std::shared_lock</code></li> <li><code>increment()</code> still uses exclusive access via <code>std::unique_lock</code></li> <li>the mutex type is <code>std::shared_mutex</code></li> </ul> <p>With this change, many threads can call <code>get()</code> concurrently, writes remain fully protected, and read scalability improves with almost no extra complexity/</p> <p>On Compiler Explorer - <a href="https://godbolt.org/z/W1es4qM8x">https://godbolt.org/z/W1es4qM8x</a> - I&rsquo;m getting:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">reader 0 sees 0 </span></span><span class="line"><span class="cl">reader 1 sees 0 </span></span><span class="line"><span class="cl">reader 2 sees 0 </span></span><span class="line"><span class="cl">reader 3 sees 1 </span></span><span class="line"><span class="cl">reader 1 sees 1 </span></span><span class="line"><span class="cl">reader 0 sees 1 </span></span><span class="line"><span class="cl">reader 2 sees 1 </span></span><span class="line"><span class="cl">reader 3 sees 1 </span></span><span class="line"><span class="cl">reader 1 sees 2 </span></span><span class="line"><span class="cl">reader 0 sees 2 </span></span><span class="line"><span class="cl">reader 2 sees 2 </span></span><span class="line"><span class="cl">reader 3 sees 2 </span></span><span class="line"><span class="cl">reader 3 sees 2 </span></span><span class="line"><span class="cl">reader 1 sees 2 </span></span><span class="line"><span class="cl">reader 0 sees 2 </span></span><span class="line"><span class="cl">reader 2 sees 2 </span></span><span class="line"><span class="cl">reader 1 sees 3 </span></span><span class="line"><span class="cl">reader 2 sees 3 </span></span><span class="line"><span class="cl">reader 3 sees 3 </span></span><span class="line"><span class="cl">reader 0 sees 3 </span></span><span class="line"><span class="cl">reader 2 sees 4 </span></span><span class="line"><span class="cl">reader 1 sees 4 </span></span><span class="line"><span class="cl">reader 3 sees 4 </span></span><span class="line"><span class="cl">reader 0 sees 4 </span></span><span class="line"><span class="cl">reader 2 sees 4 </span></span><span class="line"><span class="cl">reader 1 sees 5 </span></span><span class="line"><span class="cl">reader 3 sees 5 </span></span><span class="line"><span class="cl">reader 0 sees 5 </span></span><span class="line"><span class="cl">reader 3 sees 5 </span></span><span class="line"><span class="cl">reader 1 sees 5 </span></span><span class="line"><span class="cl">reader 0 sees 5 </span></span><span class="line"><span class="cl">reader 2 sees 5 </span></span><span class="line"><span class="cl">reader 3 sees 6 </span></span><span class="line"><span class="cl">reader 0 sees 6 </span></span><span class="line"><span class="cl">reader 2 sees 6 </span></span><span class="line"><span class="cl">reader 1 sees 6 </span></span><span class="line"><span class="cl">reader 3 sees 6 </span></span><span class="line"><span class="cl">reader 0 sees 7 </span></span><span class="line"><span class="cl">reader 2 sees 7 </span></span><span class="line"><span class="cl">reader 1 sees 7 </span></span></code></pre></div><p>The output is still nondeterministic, and it may look similar between <code>std::mutex</code> and <code>std::shared_mutex</code>. The key difference is not the values printed, but the fact that with <code>std::shared_mutex</code> multiple readers can hold the lock at the same time. This matters when the protected read section is non-trivial (parsing, lookups, copying data, etc.) and when the program is under real contention.</p> <h2 id="measuring-gains"> Measuring gains <a class="hash-link" href="#measuring-gains" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Ok, but let&rsquo;s try to measure the gains to see the difference. I&rsquo;ll add some extra sleep code to simulate a real &ldquo;workload&rdquo;, and then we can compare times.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;mutex&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;shared_mutex&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;thread&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono_literals</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// Simulated work while holding the lock </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="k">auto</span> <span class="n">ReadWork</span> <span class="o">=</span> <span class="mi">2</span><span class="n">ms</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="k">auto</span> <span class="n">WriteWork</span> <span class="o">=</span> <span class="mi">1</span><span class="n">ms</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="k">auto</span> <span class="n">GapWork</span> <span class="o">=</span> <span class="mi">1</span><span class="n">ms</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// --- Version 1: std::mutex (exclusive for both read and write) --- </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">class</span> <span class="nc">CounterMutex</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">get</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">lock_guard</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">mutex</span><span class="o">&gt;</span> <span class="n">lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep_for</span><span class="p">(</span><span class="n">ReadWork</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">value_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">increment</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">lock_guard</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">mutex</span><span class="o">&gt;</span> <span class="n">lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="o">++</span><span class="n">value_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep_for</span><span class="p">(</span><span class="n">WriteWork</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">mutable</span> <span class="n">std</span><span class="o">::</span><span class="n">mutex</span> <span class="n">mutex_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">value_</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// --- Version 2: std::shared_mutex (shared reads, exclusive writes) --- </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">class</span> <span class="nc">CounterSharedMutex</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">get</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">shared_lock</span> <span class="n">lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep_for</span><span class="p">(</span><span class="n">ReadWork</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">value_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">increment</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">unique_lock</span> <span class="n">lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="o">++</span><span class="n">value_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep_for</span><span class="p">(</span><span class="n">WriteWork</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">mutable</span> <span class="n">std</span><span class="o">::</span><span class="n">shared_mutex</span> <span class="n">mutex_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">value_</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">run_test</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">label</span><span class="p">,</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">counter</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">constexpr</span> <span class="kt">int</span> <span class="n">kReaders</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">constexpr</span> <span class="kt">int</span> <span class="n">kReadsPerReader</span> <span class="o">=</span> <span class="mi">30</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">constexpr</span> <span class="kt">int</span> <span class="n">kWrites</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">start</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">steady_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">jthread</span><span class="o">&gt;</span> <span class="n">threads</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">threads</span><span class="p">.</span><span class="n">reserve</span><span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">kReaders</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Writer </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">threads</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">([</span><span class="o">&amp;</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">kWrites</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">counter</span><span class="p">.</span><span class="n">increment</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep_for</span><span class="p">(</span><span class="n">GapWork</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Readers </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">id</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">id</span> <span class="o">&lt;</span> <span class="n">kReaders</span><span class="p">;</span> <span class="o">++</span><span class="n">id</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">threads</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">([</span><span class="o">&amp;</span><span class="n">counter</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">kReadsPerReader</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">counter</span><span class="p">.</span><span class="n">get</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep_for</span><span class="p">(</span><span class="n">GapWork</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">end</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">steady_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">ms</span> <span class="o">=</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">duration_cast</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">milliseconds</span><span class="o">&gt;</span><span class="p">(</span><span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{}: {} ms&#34;</span><span class="p">,</span> <span class="n">label</span><span class="p">,</span> <span class="n">ms</span><span class="p">.</span><span class="n">count</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;hardware_concurrency: {}&#34;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kr">thread</span><span class="o">::</span><span class="n">hardware_concurrency</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">CounterMutex</span> <span class="n">counter_mutex</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">CounterSharedMutex</span> <span class="n">counter_shared</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">run_test</span><span class="p">(</span><span class="s">&#34;std::mutex&#34;</span><span class="p">,</span> <span class="n">counter_mutex</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">run_test</span><span class="p">(</span><span class="s">&#34;std::shared_mutex&#34;</span><span class="p">,</span> <span class="n">counter_shared</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See at <a href="https://godbolt.org/z/KaxEYecWM">Compiler Explorer</a>. The output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">hardware_concurrency: 2 </span></span><span class="line"><span class="cl">std::mutex: 285 ms </span></span><span class="line"><span class="cl">std::shared_mutex: 102 ms </span></span></code></pre></div><p>On this machine, <code>std::thread::hardware_concurrency()</code> reports 2 hardware threads. In this setup, the workload is intentionally read-heavy and each read holds the lock for a short but non-trivial amount of time. With <code>std::mutex</code>, all reads and writes use exclusive locking, so reader threads are effectively serialized and must wait for each other. As a result, the total runtime is about 285 ms.</p> <p>With <code>std::shared_mutex</code>, read operations acquire a shared lock and can therefore run concurrently. On a system with two hardware threads, this allows two readers to make progress at the same time, significantly reducing contention. Under the same workload and timing parameters, the total runtime drops to about 102 ms. The exact numbers will vary between runs and platforms. Still, the difference clearly illustrates the main advantage of <code>std::shared_mutex</code> for read-mostly workloads: improved throughput when multiple readers can proceed in parallel.</p> <h2 id="a-more-realistic-example-read-mostly-cache"> A More Realistic Example: Read-Mostly Cache <a class="hash-link" href="#a-more-realistic-example-read-mostly-cache" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The &ldquo;counter&rdquo; example is small, but the pattern becomes more useful with real data structures. A typical example is a cache.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;shared_mutex&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unordered_map&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Cache</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">get</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">key</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">shared_lock</span> <span class="n">lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">data_</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">key</span><span class="p">);</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">data_</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{};</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">put</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">key</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">unique_lock</span> <span class="n">lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">data_</span><span class="p">[</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">key</span><span class="p">)]</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">value</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">mutable</span> <span class="n">std</span><span class="o">::</span><span class="n">shared_mutex</span> <span class="n">mutex_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">unordered_map</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">data_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span></code></pre></div><p>This pattern appears often in real systems:</p> <ul> <li>many threads read cached values</li> <li>updates are relatively rare</li> <li>correctness is more important than extreme micro-optimizations</li> </ul> <p>Using <code>std::shared_mutex</code> allows reads to scale while still keeping writes safe.</p> <h2 id="common-pitfalls"> Common Pitfalls <a class="hash-link" href="#common-pitfalls" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <h4 id="recursive-locking-is-undefined"> Recursive locking is undefined </h4> <p>A thread must not lock the same <code>std::shared_mutex</code> recursively:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">mutex</span><span class="p">.</span><span class="n">lock</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="n">mutex</span><span class="p">.</span><span class="n">lock</span><span class="p">();</span> <span class="c1">// undefined behavior </span></span></span></code></pre></div><p>This applies to both shared and exclusive ownership.</p> <h4 id="you-cannot-upgrade-a-shared-lock"> You cannot upgrade a shared lock </h4> <p>This pattern will deadlock:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">shared_lock</span> <span class="n">read_lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">unique_lock</span> <span class="n">write_lock</span><span class="p">(</span><span class="n">mutex_</span><span class="p">);</span> <span class="c1">// bad idea </span></span></span></code></pre></div><p>If upgrading is required, the locking strategy usually needs to change.</p> <h4 id="more-locks-do-not-always-mean-more-performance"> More locks do not always mean more performance </h4> <p><code>std::shared_mutex</code> has overhead. If:</p> <ul> <li>writes are frequent</li> <li>contention is low</li> <li>critical sections are small</li> </ul> <p>then <code>std::mutex</code> may be just as fast or even faster. Measuring is important.</p> <p>You can read this recent article about some detailed measurements: <a href="https://techfortalk.co.uk/2026/01/03/when-stdshared_mutex-outperforms-stdmutex-a-google-benchmark-study/#Performance-comparison-std-mutex-vs-std-shared-mutex">When std::shared_mutex Outperforms std::mutex: A Google Benchmark Study – Tech For Talk</a></p> <h2 id="newer-concurrency-tools-in-c20-and-above"> Newer Concurrency Tools in C++20 and Above <a class="hash-link" href="#newer-concurrency-tools-in-c20-and-above" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Since C++17, the concurrency library has expanded significantly. We now have:</p> <ul> <li><code>std::jthread</code> and cooperative cancellation (C++20)</li> <li>semaphores, latches, and barriers (C++20)</li> <li>improved atomic operations (C++20)</li> <li>safe memory reclamation mechanisms (RCU, hazard pointers in C++26)</li> </ul> <p>These tools focus mostly on thread lifetime, coordination, cancellation or lock-free programming.</p> <p><code>std::shared_mutex</code> fills a different role.</p> <p>It is still a mutual-exclusion primitive, explicitly designed to protect a shared state with many readers and few writers. It does not compete with atomics, condition variables, or RCU.</p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In this article, we explored <code>std::shared_mutex</code>, a synchronization primitive designed for protecting read-mostly shared data. Unlike <code>std::mutex</code>, it allows multiple threads to read the same resource concurrently, while still ensuring exclusive access for writers.</p> <p>Starting from a simple counter example, we showed how a plain mutex serializes all access and how switching to <code>std::shared_mutex</code> enables concurrent reads with only small changes to the code. A simple benchmark experiment demonstrated that, under a read-heavy workload, this can significantly reduce contention and improve throughput.</p> <p>Even with newer concurrency features added in C++20 and later, <code>std::shared_mutex</code> remains a useful and practical tool when reads dominate writes and simplicity is preferred over more complex synchronization techniques.</p> <h2 id="references"> References <a class="hash-link" href="#references" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li><a href="https://amzn.to/4a4FeZ3">C++ Concurrency in Action 2nd Edition</a> - by Anthony Williams</li> <li><a href="https://amzn.to/3MyZpqh">Programming: Principles and Practice Using C++ 3rd Edition</a> - by Bjarne Stroustrup</li> <li><a href="https://amzn.to/4rqnJcP">Concurrency with Modern C++: What every professional C++ programmer should know about concurrency</a> - by Rainer Grimm</li> <li><a href="https://learn.microsoft.com/en-us/cpp/standard-library/shared-mutex?view=msvc-170">&lt;shared_mutex&gt; | Microsoft Learn</a></li> <li><a href="https://en.cppreference.com/w/cpp/thread/shared_mutex.html">std::shared_mutex - cppreference.com</a></li> </ul> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Have you tried <code>shared_mutex</code>? In what situations?</li> <li>Do you use concurrency tools from C++20 and above?</li> </ul> <p>Share your comments below</p> IIFE for Complex Initialization https://www.cppstories.com/2016/11/iife-for-complex-initialization/ Sat, 24 Jan 2026 00:00:00 +0000 https://www.cppstories.com/2016/11/iife-for-complex-initialization/ <p>What do you do when the code for a variable initialization is complicated? Do you move it to another method or write inside the current scope?</p> <p>In this blog post, I’d like to present a trick that allows computing a value for a variable, even a const variable, with a compact notation.</p> <blockquote class="hint note"> Updated in Jan 2026: improved code, added C++26 section, added <code>[&amp;]</code> section, updated code samples and added links to Compiler Explorer. </blockquote> <h2 id="intro"> Intro <a class="hash-link" href="#intro" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>I hope you’re initializing most variables as <code>const</code> (so that the code is more explicit, and also compiler can reason better about the code and optimize).</p> <p>For example, it’s easy to write:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">const</span> <span class="kt">int</span> <span class="n">myParam</span> <span class="o">=</span> <span class="n">inputParam</span> <span class="o">*</span> <span class="mi">10</span> <span class="o">+</span> <span class="mi">5</span><span class="p">;</span> </span></span></code></pre></div><p>or even:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">const</span> <span class="kt">int</span> <span class="n">myParam</span> <span class="o">=</span> <span class="n">bCondition</span> <span class="o">?</span> <span class="n">inputParam</span><span class="o">*</span><span class="mi">2</span> <span class="o">:</span> <span class="n">inputParam</span> <span class="o">+</span> <span class="mi">10</span><span class="p">;</span> </span></span></code></pre></div><p>But what about complex expressions? When we have to use several lines of code, or when the <code>?</code> operator is not sufficient.</p> <p>‘It’s easy’ you say: you can wrap that initialization into a separate function.</p> <p>While that’s the right answer in most cases, I’ve noticed that in reality a lot of people write code in the current scope. That forces you to stop using <code>const</code> and code is a bit uglier.</p> <p>You might see something like this:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">myVariable</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// this should be const... </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">bFirstCondition</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">myVariable</span> <span class="o">=</span> <span class="n">bSecondCondition</span> <span class="o">?</span> <span class="n">computeFunc</span><span class="p">(</span><span class="n">inputParam</span><span class="p">)</span> <span class="o">:</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">myVariable</span> <span class="o">=</span> <span class="n">inputParam</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// more code of the current function... </span></span></span><span class="line"><span class="cl"><span class="c1">// and we assume &#39;myVariable` is const now </span></span></span></code></pre></div><p>The code above computes <code>myVariable</code> which should be <code>const</code>. But since we cannot initialize it in one line, then the <code>const</code> modifier is dropped.</p> <p>I highly suggest wrapping such code into a separate method, but recently I’ve come across a new option.</p> <p>I’ve got the idea from a great talk by <a href="https://twitter.com/lefticus">Jason Turner</a> about <a href="https://www.youtube.com/watch?v=lNnBExDoNSQ">“Practical Performance Practices”</a> where among various tips I’ve noticed <a href="https://en.wikipedia.org/wiki/Immediately-invoked_function_expression"><strong>“IIFE”</strong></a>.</p> <p>The <strong>IIFE</strong> acronym stands for <em>“Immediately-invoked function expression”</em>. Thanks to lambda expression, it’s now available in C++. We can use it for complex initialization of variables.</p> <p>Extra: You might also encounter: <strong>IILE</strong>, which stands for <em>“Immediately Invoked Lambda Expression”</em>.</p> <p>How does it look like?</p> <h2 id="iife"> IIFE <a class="hash-link" href="#iife" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The main idea behind IIFE is to write a small lambda that computes the value:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">const</span> <span class="k">auto</span> <span class="n">var</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">...]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="cm">/* some complex code here */</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}();</span> <span class="c1">// call it! </span></span></span></code></pre></div><p><code>var</code> is <code>const</code> even when you need several lines of code to initialize it!</p> <p>The critical bit is to call the lambda at the end. Otherwise it’s just a definition.</p> <p>The imaginary code from the previous section could be rewritten to:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">const</span> <span class="kt">int</span> <span class="n">myVariable</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">bFirstCondition</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">bSecondCondition</span> <span class="o">?</span> <span class="n">computeFunc</span><span class="p">(</span><span class="n">inputParam</span><span class="p">)</span> <span class="o">:</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">inputParam</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}();</span> <span class="c1">// call! </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"><span class="c1">// more code of the current function... </span></span></span></code></pre></div><p>The above example shows that the original code was enclosed in a lambda.</p> <p>We can also be more expressive and capture only needed things:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">const</span> <span class="kt">int</span> <span class="n">myVariable</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="n">inputParam</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">bFirstCondition</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">bSecondCondition</span> <span class="o">?</span> <span class="n">computeFunc</span><span class="p">(</span><span class="n">inputParam</span><span class="p">)</span> <span class="o">:</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">inputParam</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}();</span> <span class="c1">// call! </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"><span class="c1">// more code of the current function... </span></span></span></code></pre></div><p>The expression takes no parameters but captures the current scope by reference (or some explicit variables). Also, look at the last line of the declaration, <code>()</code> - we’re invoking the function immediately.</p> <p>Additionally, since this lambda takes no parameters, we can skip <code>()</code> in the declaration. Only <code>[]</code> is required at the beginning, since it’s the <em>lambda-introducer</em> .</p> <h2 id="improving-readability-of-iife"> Improving Readability of IIFE <a class="hash-link" href="#improving-readability-of-iife" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>One of the main concerns behind IIFE is readability. Sometimes it’s not easy to see that <code>()</code> at the end.</p> <p>How can we fix that?</p> <p>Some people suggest declaring a lambda above the variable declaration and just calling it later:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">initialiser</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="cm">/* some complex code here */</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">auto</span> <span class="n">var</span> <span class="o">=</span> <span class="n">initialiser</span><span class="p">();</span> <span class="c1">// call it </span></span></span></code></pre></div><p>The issue here is that you need to find a name for the initializer lambda, but I agree that’s easy to read.</p> <p>And another technique involves <code>std::invoke()</code> that is expressive and shows that we’re calling something:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">const</span> <span class="k">auto</span> <span class="n">var</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">invoke</span><span class="p">([</span><span class="o">&amp;</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="cm">/* some complex code here */</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">});</span> </span></span></code></pre></div><p><strong>Note</strong>: <code>std::invoke()</code> is located in the <code>&lt;functional&gt;</code> header and it’s available since C++17.</p> <p>In the above example, you can see that we clearly express our intention, so it might be easier to read such code.</p> <p>Now back to you:</p> <p>Which method do you prefer?</p> <ul> <li>just calling <code>()</code> at the end of the anonymous lambda?</li> <li>giving a name to the lambda and calling it later?</li> <li>using <code>std::invoke()</code></li> <li>something else?</li> </ul> <h2 id="should-we-capture-the-whole-context-with--"> Should we capture the whole context with <code>&amp;</code> ? <a class="hash-link" href="#should-we-capture-the-whole-context-with--" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Short answer: capture only what you need.</p> <p>Using <code>[&amp;]</code> is concise and mirrors the “local scope” feel of the original code. But capture‑all by reference hides dependencies and makes it easy to accidentally use something that later becomes a dangling reference.</p> <p>That&rsquo;s why it&rsquo;s best to write:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">const</span> <span class="k">auto</span> <span class="n">value</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="n">inputParam</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">anotherValue</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// ... </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">return</span> <span class="cm">/* computed value */</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}();</span> </span></span></code></pre></div><p>[&amp;] is convenient and safe for IIFE in most cases, but it’s also the least explicit. For code that will evolve or be reviewed often, prefer a precise capture list to make dependencies obvious and avoid surprises.</p> <h2 id="c26-updates"> C++26 Updates <a class="hash-link" href="#c26-updates" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1102r2.html">P1102R2: Down with ()!</a></p> <p>From the start of the article I wrote that you don&rsquo;t need to write <code>()</code> to indicate the argument list&hellip; but until C++26 we had had to write:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">const</span> <span class="k">auto</span> <span class="n">value</span> <span class="o">=</span> <span class="p">[</span><span class="n">inputParam</span><span class="p">]()</span> <span class="k">noexcept</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="cm">/*condition*/</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">inputParam</span><span class="o">*</span><span class="mf">2.0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">inputParam</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}();</span> </span></span></code></pre></div><p>Do you see <code>[]() noexcept</code>&hellip; ?</p> <p>Up to C++26 there was a limitation:</p> <blockquote> <p>Confusingly, the current Standard requires the empty parens when using the <code>mutable</code> (an other) keyword. This rule is unintuitive, causes common syntax errors, and clutters our code.</p> </blockquote> <p>This also applied to <code>noexcept</code>, attributes and other specifiers.</p> <p>In summary, since C++26 you can omit the <code>()</code> if there are no parameters to declare/pass to the lambda.</p> <h2 id="use-case-of-iife"> Use Case of IIFE <a class="hash-link" href="#use-case-of-iife" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Ok, the previous examples were all super simple, and maybe even convoluted&hellip; is there a better and more practical example?</p> <p>How about building a simple HTML string?</p> <p>Our task is to produce an HTML node for a link:</p> <p>As input, you have two strings: <code>link</code> and <code>text</code> (might be empty).</p> <p>The output: a new string:</p> <p><code>&lt;a href=&quot;link&quot;&gt;text&lt;/a&gt;</code></p> <p>or</p> <p><code>&lt;a href=&quot;link&quot;&gt;link&lt;/a&gt;</code> (when <code>text</code> is empty)</p> <p>We can write a following function:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">BuildStringTest</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">link</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">text</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">html</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">html</span> <span class="o">=</span> <span class="s">&#34;&lt;a href=</span><span class="se">\&#34;</span><span class="s">&#34;</span> <span class="o">+</span> <span class="n">link</span> <span class="o">+</span> <span class="s">&#34;</span><span class="se">\&#34;</span><span class="s">&gt;&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">text</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="n">html</span> <span class="o">+=</span> <span class="n">text</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">html</span> <span class="o">+=</span> <span class="n">link</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">html</span> <span class="o">+=</span> <span class="s">&#34;&lt;/a&gt;&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">html</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Alternatively we can also compact the code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">BuildStringTest2</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">link</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">text</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">html</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">inText</span> <span class="o">=</span> <span class="n">text</span><span class="p">.</span><span class="n">empty</span><span class="p">()</span> <span class="o">?</span> <span class="nl">link</span> <span class="p">:</span> <span class="n">text</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">html</span> <span class="o">=</span> <span class="s">&#34;&lt;a href=</span><span class="se">\&#34;</span><span class="s">&#34;</span> <span class="o">+</span> <span class="n">link</span> <span class="o">+</span> <span class="s">&#34;</span><span class="se">\&#34;</span><span class="s">&gt;&#34;</span> <span class="o">+</span> <span class="n">inText</span> <span class="o">+</span> <span class="s">&#34;&lt;/a&gt;&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">html</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Ideally, we’d like to have <code>html</code> as <code>const</code>, so we can rewrite it as:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">BuildStringTestIIFE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">link</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">text</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">html</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="n">link</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">text</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">out</span> <span class="o">=</span> <span class="s">&#34;&lt;a href=</span><span class="se">\&#34;</span><span class="s">&#34;</span> <span class="o">+</span> <span class="n">link</span> <span class="o">+</span> <span class="s">&#34;</span><span class="se">\&#34;</span><span class="s">&gt;&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">text</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="n">out</span> <span class="o">+=</span> <span class="n">text</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">out</span> <span class="o">+=</span> <span class="n">link</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">out</span> <span class="o">+=</span> <span class="s">&#34;&lt;/a&gt;&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">out</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}();</span> <span class="c1">// call ()! </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">html</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Or with a more compact code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">BuildStringTestIIFE2</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">link</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">text</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">html</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="n">link</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">text</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">inText</span> <span class="o">=</span> <span class="n">text</span><span class="p">.</span><span class="n">empty</span><span class="p">()</span> <span class="o">?</span> <span class="nl">link</span> <span class="p">:</span> <span class="n">text</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s">&#34;&lt;a href=</span><span class="se">\&#34;</span><span class="s">&#34;</span> <span class="o">+</span> <span class="n">link</span> <span class="o">+</span> <span class="s">&#34;</span><span class="se">\&#34;</span><span class="s">&gt;&#34;</span> <span class="o">+</span> <span class="n">inText</span> <span class="o">+</span> <span class="s">&#34;&lt;/a&gt;&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}();</span> <span class="c1">// call! </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">html</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Here’s the code <a href="https://godbolt.org/z/GePnoxod3">@Compiler Explorer</a></p> <p>Do you think that’s acceptable?</p> <p>Try rewriting the example below, maybe you can write nicer code?</p> <h2 id="a-benchmark-of-iife"> A Benchmark of IIFE <a class="hash-link" href="#a-benchmark-of-iife" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>With IIFE, we not only get a clean way to initialize <code>const</code> variables, but since we have more <code>const</code> objects, we might get better performance.</p> <p>Is that true? Or maybe longer code and creation of lambda makes things slower?</p> <p>For the HTML example, I wrote a benchmark that tests all four version:</p> <p><a href="http://quick-bench.com/_DCQLNBmbXH50IJLnVRqXjJ7jlY">@QuickBench</a></p> <p>And it looks like we’re getting 10% with IIFE! (also similar result with recent compilers, as of 2026)</p> <p><img src="https://4.bp.blogspot.com/-jeVzCwfF3wg/XaqVRQbUQQI/AAAAAAAAD-w/eo7RfqxUxCUsn6e6ppGt1sa-1PJ4p5uRgCLcBGAsYHQ/s1600/iifebench.png" alt="IIFE C++ Benchmark"><br> Some notes:</p> <ul> <li>This code shows the rough impact of the IIFE technique, but it was not written to get the super-fast performance. We’re manipulating string here so many factors can affect the final result.</li> <li>it seems that if you have less temporary variables, the code runs faster (so <code>StringBuild</code> is slightly faster than <code>StringBuild2</code> and similarly IIFE and IIFE2)</li> <li>We can also use <code>string::reserve</code> to preallocate memory, so that each new string addition won’t cause reallocation.</li> </ul> <p>You can check other tests here: <a href="http://quick-bench.com/9nCgWpht-ZUOlI6sTBiQET70RZY">@QuickBench</a>, and see the recent version <a href="https://quick-bench.com/q/hwGBf5WlXfVTvdBZrE60eMxC5V0">@QuickBench Clang 17.0</a></p> <p>It looks like the performance is not something you need to be concerned with. The code works sometimes faster, and in most of the cases the compiler should be able to generate similar code as the initial local version</p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Would you use such a thing in your code?</p> <p>In C++ Coding Guideline we have a suggestion that it’s viable to use it for complex init code:</p> <p><a href="http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-lambda-init">C++ Core Guidelines - ES.28: Use lambdas for complex initialization,</a></p> <p>I am a bit sceptical to such expression, but I probably need to get used to it. I wouldn’t use it for a long code. It’s perhaps better to wrap some long code into a separate method and give it a proper name. But if the code is 2 or three lines long… maybe why not.</p> <p>Also, if you use this technique, make sure it’s readable. Leveraging <code>std::invoke()</code> seems to be a great option.</p> <p>I want to thank Mariusz Jaskółka from for the review, hints about compacting the code and also perf improvements with <code>reserve()</code>.</p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>What do you think about such syntax? Have you used it in your projects?</li> <li>Do you have any guidelines about such thing?</li> <li>Is such expression better than having lots of small functions?</li> </ul> <h2 id="references-and-books"> References and Books <a class="hash-link" href="#references-and-books" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li><a href="https://herbsutter.com/2013/04/05/complex-initialization-for-a-const-variable/">Herb Sutter Blog: Complex initialization for a const variable</a></li> <li><a href="https://www.youtube.com/watch?v=_CbBfuQQQI8">C++ Weekly - Ep 32 - Lambdas For Free</a></li> <li><a href="http://articles.emptycrate.com/2014/12/16/complex_object_initialization_optimization_with_iife_in_c11.html">Complex Object Initialization Optimization with IIFE in C++11</a> - from Jason Turner’s Blog</li> <li><a href="https://youtu.be/d4nmNYTM1j8">C++ IIFE in quick-bench.com</a></li> <li><a href="http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-lambda-init">C++ Core Guidelines - ES.28: Use lambdas for complex initialization,</a></li> </ul> <p>Books:</p> <ul> <li><a href="https://amzn.to/4huhBwt">C++20 - The Complete Guide by Nicolai M. Josuttis</a> @Amazon</li> <li><a href="https://amzn.to/48OaFI9">Modern C++ Programming Cookbook: Master C++ core language and standard library features, with over 100 recipes, updated to C++20 2nd ed. Edition</a> @Amazon</li> </ul> 7 Practical std::chrono Calendar Examples (C++20) https://www.cppstories.com/2025/chrono-calendar-examples/ Tue, 30 Dec 2025 00:00:00 +0000 https://www.cppstories.com/2025/chrono-calendar-examples/ <p>This article collects small, self-contained, and practical examples for working with <code>std::chrono</code> calendar types.</p> <p>The previous blog post - see <a href="https://www.cppstories.com/2025/chrono-calendar-types/">Exploring C++20 std::chrono - Calendar Types - C++ Stories</a> - focused on the building blocks: calendar types, operators, and arithmetic rules. In this post, we&rsquo;ll focus on practical examples like:</p> <ul> <li>What’s the last business day of the month?</li> <li>When is the third Friday in June?</li> <li>How many days since the start of the year?</li> <li>What happens when I add a month to January 31?</li> <li>And a few more</li> </ul> <p>Let&rsquo;s start.</p> <h2 id="1-which-day-of-the-year-is-that"> 1. Which day of the year is that? <a class="hash-link" href="#1-which-day-of-the-year-is-that" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Let&rsquo;s begin with a simple example of counting how many days a specific date is from the start of the year. In the previous article, we covered basic arithmetic, so now we can apply that knowledge to calculate the difference between a given date and the beginning of the year.</p> <p>See below:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">ordinal_suffix</span><span class="p">(</span><span class="k">const</span> <span class="n">days</span><span class="o">&amp;</span> <span class="n">d</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">n</span> <span class="o">=</span> <span class="n">d</span><span class="p">.</span><span class="n">count</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">last_two</span> <span class="o">=</span> <span class="n">n</span> <span class="o">%</span> <span class="mi">100</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">last_two</span> <span class="o">&gt;=</span> <span class="mi">11</span> <span class="o">&amp;&amp;</span> <span class="n">last_two</span> <span class="o">&lt;=</span> <span class="mi">13</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s">&#34;th&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">switch</span> <span class="p">(</span><span class="n">n</span> <span class="o">%</span> <span class="mi">10</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="mi">1</span><span class="o">:</span> <span class="k">return</span> <span class="s">&#34;st&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="mi">2</span><span class="o">:</span> <span class="k">return</span> <span class="s">&#34;nd&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="mi">3</span><span class="o">:</span> <span class="k">return</span> <span class="s">&#34;rd&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">default</span><span class="o">:</span> <span class="k">return</span> <span class="s">&#34;th&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">print_day_of_year</span><span class="p">(</span><span class="n">year_month_day</span> <span class="n">ymd</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">sys_days</span> <span class="n">start_of_year</span><span class="p">{</span> <span class="n">ymd</span><span class="p">.</span><span class="n">year</span><span class="p">()</span> <span class="o">/</span> <span class="n">January</span> <span class="o">/</span> <span class="mi">1</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">sys_days</span> <span class="n">current</span><span class="p">{</span> <span class="n">ymd</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">days</span> <span class="n">day_index</span> <span class="o">=</span> <span class="p">(</span><span class="n">current</span> <span class="o">-</span> <span class="n">start_of_year</span><span class="p">)</span> <span class="o">+</span> <span class="n">days</span><span class="p">{</span><span class="mi">1</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} is the {}{} day of the year</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">ymd</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">day_index</span><span class="p">.</span><span class="n">count</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="n">ordinal_suffix</span><span class="p">(</span><span class="n">day_index</span><span class="p">));</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">print_day_of_year</span><span class="p">(</span><span class="mi">2025</span><span class="n">y</span> <span class="o">/</span> <span class="n">January</span> <span class="o">/</span> <span class="mi">2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">print_day_of_year</span><span class="p">(</span><span class="mi">2025</span><span class="n">y</span> <span class="o">/</span> <span class="n">November</span> <span class="o">/</span> <span class="mi">11</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run here <a href="https://godbolt.org/z/1vq5Efrnv">@Compiler Explorer</a></p> <p>A few small details worth noticing:</p> <ul> <li>The arithmetic is done entirely in <code>sys_days</code>.</li> <li>The result is one-based (January 1 is day 1), which is usually what people expect.</li> <li>Leap years fall out naturally from the <code>sys_days</code> conversion.</li> </ul> <h2 id="2-nth-weekday-of-a-month"> 2. Nth weekday of a month <a class="hash-link" href="#2-nth-weekday-of-a-month" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>If you want to check the date of the third Friday in a given month:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">literals</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">thirdFriday</span> <span class="o">=</span> <span class="mi">2026</span><span class="n">y</span> <span class="o">/</span> <span class="n">June</span> <span class="o">/</span> <span class="n">Friday</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Third Friday of {:%B %Y}: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">thirdFriday</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">sys_days</span><span class="p">{</span><span class="n">thirdFriday</span><span class="p">});</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run at <a href="https://godbolt.org/z/PonjYrYqc">Compiler Explorer</a></p> <p>The type of <code>thirdFriday</code> is <code>year_month_weekday</code>, and if we want to show it as a full date, we can convert it to <code>sys_days</code>.</p> <h2 id="3-last-day-of-the-month"> 3. Last day of the month <a class="hash-link" href="#3-last-day-of-the-month" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>End-of-month logic sounds simple, but it can be painful to implement. With <code>year_month_day_last</code> it&rsquo;s now super simple:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">year_month_day_last</span> <span class="n">endOfFeb2025</span> <span class="o">=</span> </span></span><span class="line"><span class="cl"> <span class="n">year</span><span class="p">{</span><span class="mi">2025</span><span class="p">}</span> <span class="o">/</span> <span class="n">February</span> <span class="o">/</span> <span class="n">last</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">year_month_day_last</span> <span class="n">endOfFeb2024</span> <span class="o">=</span> </span></span><span class="line"><span class="cl"> <span class="n">year</span><span class="p">{</span><span class="mi">2024</span><span class="p">}</span> <span class="o">/</span> <span class="n">February</span> <span class="o">/</span> <span class="n">last</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">sys_days</span><span class="p">{</span><span class="n">endOfFeb2025</span><span class="p">});</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">sys_days</span><span class="p">{</span><span class="n">endOfFeb2024</span><span class="p">});</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See at <a href="https://godbolt.org/z/ePh54oPob">Compiler Explorer</a></p> <p>Output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">2025-02-28 </span></span><span class="line"><span class="cl">2024-02-29 </span></span></code></pre></div><p>Again, we need to convert to <code>sys_days</code> to print the date; otherwise, you will see something like <code>2025/Feb/last</code>.</p> <h2 id="4-computing-last-dates-for-the-whole-year"> 4. Computing &ldquo;last&rdquo; dates for the whole year <a class="hash-link" href="#4-computing-last-dates-for-the-whole-year" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>We previously computed the n-th weekday, but how can we determine the last weekday of a month? This is useful for payrolls, meetings, and similar purposes.</p> <p>The nice part is that this is exactly what <code>weekday[last]</code> is for:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">2026</span><span class="n">y</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="n">m</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">m</span> <span class="o">&lt;=</span> <span class="mi">12</span><span class="p">;</span> <span class="o">++</span><span class="n">m</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">lastFriday</span> <span class="o">=</span> <span class="n">y</span> <span class="o">/</span> <span class="n">m</span> <span class="o">/</span> <span class="n">Friday</span><span class="p">[</span><span class="n">last</span><span class="p">];</span> </span></span><span class="line"><span class="cl"> <span class="n">sys_days</span> <span class="n">date</span> <span class="o">=</span> <span class="n">sys_days</span><span class="p">{</span><span class="n">lastFriday</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{:%B %Y}: last Friday is {:%F}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">date</span><span class="p">,</span> <span class="n">date</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Example output (shape):</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">January 2026: last Friday is 2026-01-30 </span></span><span class="line"><span class="cl">February 2026: last Friday is 2026-02-27 </span></span><span class="line"><span class="cl">... </span></span><span class="line"><span class="cl">December 2026: last Friday is 2026-12-25 </span></span></code></pre></div><p><strong>Warning:</strong> The loop <code>for (month m = January; m &lt;= December; ++m)</code> will not work as intended. It creates an infinite loop because <code>++m</code> uses modulo arithmetic, which wraps it back to January.</p> <h2 id="5-adding-months"> 5. Adding months <a class="hash-link" href="#5-adding-months" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Month arithmetic in <code>&lt;chrono&gt;</code> is field-based, not duration-based. That distinction matters, especially once you involve <code>sys_days</code>.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">year_month_day</span> <span class="n">jan31</span><span class="p">{</span> <span class="n">year</span><span class="p">{</span><span class="mi">2025</span><span class="p">}</span> <span class="o">/</span> <span class="n">January</span> <span class="o">/</span> <span class="mi">31</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">feb</span> <span class="o">=</span> <span class="n">jan31</span> <span class="o">+</span> <span class="n">months</span><span class="p">{</span><span class="mi">1</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Jan 31 + 1 month = {}, ok: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">feb</span><span class="p">,</span> <span class="n">feb</span><span class="p">.</span><span class="n">ok</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/W8WYWPE7j">@Compiler Explorer</a></p> <p>Output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Jan 31 + 1 month = 2025-02-31 is not a valid date, ok: false </span></span></code></pre></div><p>This is intentional. Adding <code>months</code> to a <code>year_month_day</code> preserves the day field, even if the result is not a valid civil date. The library does not clamp or normalize automatically.</p> <p>How to clamp the result and get the correct date?</p> <p>If you first perform calendar arithmetic and then convert to <code>sys_days</code>, overflow is normalized into the following month:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">normalized</span> <span class="o">=</span> <span class="n">sys_days</span><span class="p">{</span> <span class="n">jan31</span> <span class="o">+</span> <span class="n">months</span><span class="p">{</span><span class="mi">1</span><span class="p">}</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Normalized via sys_days: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">year_month_day</span><span class="p">{</span><span class="n">normalized</span><span class="p">});</span> </span></span></code></pre></div><p>Output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Normalized via sys_days: 2025-03-03 </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/fodEKn886">@Compiler Explorer</a></p> <p>What happens here:</p> <ul> <li><code>jan31 + months{1}</code> is <code>2025-02-31</code> (invalid, but allowed)</li> <li>Converting to <code>sys_days</code> forces normalization</li> <li>February 2025 has 28 days</li> <li>February 31 overflows by 3 days so we get March 3</li> </ul> <p>You can also try a different &ldquo;order&rdquo;:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">durationBased</span> <span class="o">=</span> <span class="n">sys_days</span><span class="p">{</span><span class="n">jan31</span><span class="p">}</span> <span class="o">+</span> <span class="n">months</span><span class="p">{</span><span class="mi">1</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Duration-based result: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">durationBased</span><span class="p">);</span> </span></span></code></pre></div><p>Typical output (libstdc++):</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">2025-03-02 10:29:06 </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/5WhPT3ohz">@Compiler Explorer</a></p> <p>Here, <code>months{1}</code> is treated as an average month duration (30 days, 10 hours, 29 minutes, 6 seconds).</p> <h2 id="6-next-business-day"> 6. Next business day <a class="hash-link" href="#6-next-business-day" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>A very common rule in finance is &ldquo;move to the next business day&rdquo;. Settlement dates, payment processing, and reporting cutoffs often use this exact logic, at least as a baseline.</p> <p>For now, we’ll define a business day as Monday to Friday, skipping weekends. Holidays can be layered on later without changing the structure of the code.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">sys_days</span> <span class="nf">next_business_day</span><span class="p">(</span><span class="n">sys_days</span> <span class="n">d</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="p">(</span><span class="nb">true</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">d</span> <span class="o">+=</span> <span class="n">days</span><span class="p">{</span><span class="mi">1</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">weekday</span> <span class="n">wd</span><span class="p">{</span><span class="n">d</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">wd</span> <span class="o">!=</span> <span class="n">Saturday</span> <span class="o">&amp;&amp;</span> <span class="n">wd</span> <span class="o">!=</span> <span class="n">Sunday</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">d</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">sys_days</span> <span class="n">tradeDate</span> <span class="o">=</span> <span class="n">sys_days</span><span class="p">{</span> <span class="n">year</span><span class="p">{</span><span class="mi">2025</span><span class="p">}</span><span class="o">/</span><span class="n">November</span><span class="o">/</span><span class="mi">21</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">settlement</span> <span class="o">=</span> <span class="n">next_business_day</span><span class="p">(</span><span class="n">tradeDate</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Trade date: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">year_month_day</span><span class="p">{</span><span class="n">tradeDate</span><span class="p">});</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Next business day: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">year_month_day</span><span class="p">{</span><span class="n">settlement</span><span class="p">});</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">sys_days</span> <span class="n">tuesday</span> <span class="o">=</span> <span class="n">sys_days</span><span class="p">{</span> <span class="n">year</span><span class="p">{</span><span class="mi">2025</span><span class="p">}</span><span class="o">/</span><span class="n">November</span><span class="o">/</span><span class="mi">18</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Next business day after {} is {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">year_month_day</span><span class="p">{</span><span class="n">tuesday</span><span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="n">year_month_day</span><span class="p">{</span><span class="n">next_business_day</span><span class="p">(</span><span class="n">tuesday</span><span class="p">)});</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Trade date: 2025-11-21 </span></span><span class="line"><span class="cl">Next business day: 2025-11-24 </span></span><span class="line"><span class="cl">Next business day after 2025-11-18 is 2025-11-19 </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/Wb4srz13h">@Compiler Explorer</a></p> <h2 id="7-count-fridays-in-a-month"> 7. Count Fridays in a month <a class="hash-link" href="#7-count-fridays-in-a-month" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>As a last example, let&rsquo;s count how many Fridays do we have a in a given month:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">count_weekdays_in_month_simple</span><span class="p">(</span><span class="n">year_month</span> <span class="n">ym</span><span class="p">,</span> <span class="n">weekday</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">sys_days</span> <span class="n">d</span> <span class="o">=</span> <span class="n">sys_days</span><span class="p">{</span> <span class="n">ym</span> <span class="o">/</span> <span class="n">day</span><span class="p">{</span><span class="mi">1</span><span class="p">}</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="p">(</span><span class="n">year_month_day</span><span class="p">{</span><span class="n">d</span><span class="p">}.</span><span class="n">month</span><span class="p">()</span> <span class="o">==</span> <span class="n">ym</span><span class="p">.</span><span class="n">month</span><span class="p">())</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">weekday</span><span class="p">{</span><span class="n">d</span><span class="p">}</span> <span class="o">==</span> <span class="n">target</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">++</span><span class="n">count</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">d</span> <span class="o">+=</span> <span class="n">days</span><span class="p">{</span><span class="mi">1</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">count</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">unsigned</span> <span class="nf">count_weekdays_in_month</span><span class="p">(</span><span class="n">year_month</span> <span class="n">ym</span><span class="p">,</span> <span class="n">weekday</span> <span class="n">wd</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">unsigned</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">year_month_weekday</span> <span class="n">ymwd</span> <span class="o">=</span> <span class="n">ym</span> <span class="o">/</span> <span class="n">wd</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ymwd</span><span class="p">.</span><span class="n">ok</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="k">break</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">year_month_day</span> <span class="n">ymd</span><span class="p">{</span> <span class="n">ymwd</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">ymd</span><span class="p">.</span><span class="n">ok</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="o">++</span><span class="n">count</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">count</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">ym</span> <span class="o">=</span> <span class="n">year</span><span class="p">{</span><span class="mi">2025</span><span class="p">}</span> <span class="o">/</span> <span class="n">May</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">fridays</span> <span class="o">=</span> <span class="n">count_weekdays_in_month</span><span class="p">(</span><span class="n">ym</span><span class="p">,</span> <span class="n">Friday</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Fridays in {}: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ym</span><span class="p">,</span> <span class="n">fridays</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">mondays</span> <span class="o">=</span> <span class="n">count_weekdays_in_month</span><span class="p">(</span><span class="n">ym</span><span class="p">,</span> <span class="n">Monday</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Mondays in {}: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ym</span><span class="p">,</span> <span class="n">mondays</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/P879zfKee">@Compiler Explorer</a></p> <p>The code has two versions:</p> <ul> <li>The simple version iterates day by day and might not be optimal. You can theoretically speed it up by increasing by 7 days&hellip;</li> <li>In the second version, we can iterate using weekdays.</li> </ul> <p>Also, you can make the code even faster with just arthmetic, without any loops. It was suggested in <a href="https://www.reddit.com/r/cpp/comments/1q08ebk/comment/nypqx7j/">this comment at Reddit</a>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">count_weekdays_in_month</span><span class="p">(</span><span class="n">year_month</span> <span class="n">ym</span><span class="p">,</span> <span class="n">weekday</span> <span class="n">wd</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">a</span> <span class="o">=</span> <span class="n">sys_days</span><span class="p">{</span><span class="n">ym</span> <span class="o">/</span> <span class="n">wd</span><span class="p">[</span><span class="mi">1</span><span class="p">]};</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">b</span> <span class="o">=</span> <span class="n">sys_days</span><span class="p">{</span><span class="n">ym</span> <span class="o">/</span> <span class="n">wd</span><span class="p">[</span><span class="n">last</span><span class="p">]};</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">(</span><span class="n">b</span> <span class="o">-</span> <span class="n">a</span><span class="p">)</span> <span class="o">/</span> <span class="n">weeks</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See the updated example here: <a href="https://godbolt.org/z/TPK368W9f">https://godbolt.org/z/TPK368W9f</a></p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In this article we covered a set of small, practical examples built on top of the C++20 <code>&lt;chrono&gt;</code> calendar types The examples showed how to count days within a year, resolve n-th and last weekdays of a month, handle end-of-month and month-addition edge cases, distinguish between calendar and duration arithmetic, and express simple business rules such as “next business day” or counting specific weekdays in a month.</p> <p>In most cases, we have the same pattern: calendar types are used to express structure and intent, while <code>sys_days</code> is used when actual day counting, iteration, or normalization is required.</p> <h2 id="documents-and-resources"> Documents and Resources <a class="hash-link" href="#documents-and-resources" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li><a href="https://timsong-cpp.github.io/cppwp/n4868/time">C++ Standard Draft - Time section</a> - N4868 (October 2020 pre-virtual-plenary working draft/C++20 plus editorial changes)</li> <li><a href="https://amzn.to/4huhBwt">C++20 - The Complete Guide by Nicolai M. Josuttis</a> @Amazon</li> <li><a href="https://amzn.to/48OaFI9">Modern C++ Programming Cookbook: Master C++ core language and standard library features, with over 100 recipes, updated to C++20 2nd ed. Edition</a> @Amazon</li> <li><a href="https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes">https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes</a> - examples and recipes for Howard Hinnant&rsquo;s <code>tz.h</code> library, which is a base for chrono.</li> </ul> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Do you use <code>std::chrono</code> for calendar computations?</li> <li>What use cases are most important to you for a calendar-type library?</li> </ul> Exploring C++20 std::chrono - Calendar Types https://www.cppstories.com/2025/chrono-calendar-types/ Sat, 27 Dec 2025 00:00:00 +0000 https://www.cppstories.com/2025/chrono-calendar-types/ <p>Before C++20, <code>&lt;chrono&gt;</code> gave us a solid foundation for working with clocks, durations, and time points - but it didn’t really know anything about the civil calendar. If you needed to represent “March 15”, check whether a date is valid, compute “the third Monday of November”, or add a few months to a date, you had to rely on custom utilities, <code>std::tm</code>, or external libraries like Howard Hinnant’s excellent date.</p> <p>C++20 finally fills this gap by standardising a complete set of calendar types: <code>year</code>, <code>month</code>, <code>day</code>, <code>weekday</code>, <code>year_month_day</code>, <code>month_day_last</code>, and many more. These types let you express dates in a clear, strongly typed way, without fragile integer arithmetic or manual conversions.</p> <p>All of this comes with a very clean API: more than 40 overloads of the <code>/</code> operator let you build date types fluently, almost like writing calendar expressions. In short, C++20 turns most everyday date manipulation tasks into expressive, readable, and fully standard C++.</p> <p>So let&rsquo;s review the core types and operations.</p> <h2 id="introduction-to-calendar-types"> Introduction to Calendar Types <a class="hash-link" href="#introduction-to-calendar-types" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In C++20, the library extended <strong>durations types</strong> to cover days, months, and years:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">using</span> <span class="n">hours</span> <span class="o">=</span> <span class="n">duration</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">ratio</span><span class="o">&lt;</span><span class="mi">3600</span><span class="o">&gt;&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// new in C++20 </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">using</span> <span class="n">days</span> <span class="o">=</span> <span class="n">duration</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">ratio_multiply</span><span class="o">&lt;</span><span class="n">ratio</span><span class="o">&lt;</span><span class="mi">24</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">hours</span><span class="o">::</span><span class="n">period</span><span class="o">&gt;&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">weeks</span> <span class="o">=</span> <span class="n">duration</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">ratio_multiply</span><span class="o">&lt;</span><span class="n">ratio</span><span class="o">&lt;</span><span class="mi">7</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">days</span><span class="o">::</span><span class="n">period</span><span class="o">&gt;&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">years</span> <span class="o">=</span> <span class="n">duration</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">ratio_multiply</span><span class="o">&lt;</span><span class="n">ratio</span><span class="o">&lt;</span><span class="mi">146097</span><span class="p">,</span> <span class="mi">400</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">days</span><span class="o">::</span><span class="n">period</span><span class="o">&gt;&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">months</span> <span class="o">=</span> <span class="n">duration</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">ratio_divide</span><span class="o">&lt;</span><span class="n">years</span><span class="o">::</span><span class="n">period</span><span class="p">,</span> <span class="n">ratio</span><span class="o">&lt;</span><span class="mi">12</span><span class="o">&gt;&gt;&gt;</span><span class="p">;</span> </span></span></code></pre></div><p>And in C++20, we have the following new calendrical types:</p> <table> <thead> <tr> <th>name</th> <th>description</th> </tr> </thead> <tbody> <tr> <td><code>last_(spec)</code></td> <td>The type is used in conjunction with other calendar types to specify the last in a sequence. For example, depending on the context, it can represent the last day of a month, or the last day of the week of a month. See examples below&hellip;</td> </tr> <tr> <td><code>day</code></td> <td>represents a day of a month. It normally holds values in the range 1 to 31, but may hold non-negative values outside this range.</td> </tr> <tr> <td><code>month</code></td> <td>represents a month of a year. It normally holds values in the range 1 to 12, but may hold non-negative values outside this range.</td> </tr> <tr> <td><code>year</code></td> <td>represents a year in the civil (Gregorian) calendar. It can represent values in the range <code>[min(), max()]</code> (static member functions). It can be constructed with any int value, which will be subsequently truncated to fit into year&rsquo;s unspecified internal storage</td> </tr> <tr> <td><code>weekday</code></td> <td>represents a day of the week in the civil calendar. It normally holds values in the range 0 to 6, corresponding to Sunday through Saturday, but it may hold non-negative values outside this range</td> </tr> <tr> <td><code>weekday_indexed</code></td> <td>represents a <code>weekday</code> and a small index in the range 1 to 5. This class is used to represent the first, second, third, fourth, or fifth weekday of a month.</td> </tr> <tr> <td><code>weekday_last</code></td> <td>represents the last weekday of a month.</td> </tr> <tr> <td><code>month_day</code></td> <td>represents a specific day of a specific month, but with an unspecified year.</td> </tr> <tr> <td><code>month_day_last</code></td> <td>represents the last day of a month.</td> </tr> <tr> <td><code>month_weekday</code></td> <td>represents the n-th weekday of a month, of an as yet unspecified year. To do this, the <code>month_weekday</code> stores a <code>month</code> and a <code>weekday_indexed</code>.</td> </tr> <tr> <td><code>month_weekday_last</code></td> <td>represents the last weekday of a month, of an as yet unspecified year. To do this, the <code>month_weekday_last</code> stores a <code>month</code> and a <code>weekday_last</code>.</td> </tr> <tr> <td><code>year_month</code></td> <td>represents a specific month of a specific year, but with an unspecified day. <code>year_month</code> is a field-based time point with a resolution of months.</td> </tr> <tr> <td><code>year_month_day</code></td> <td>represents a specific year, month, and day. <code>year_month_day</code> is a field-based time point with a resolution of days. The class supports years- and months-oriented arithmetic, but not days-oriented arithmetic. For the latter, there is a conversion to <code>sys_days</code>, which efficiently supports days-oriented arithmetic.</td> </tr> <tr> <td><code>year_month_day_last</code></td> <td>represents the last day of a specific year and month. <code>year_month_day_last</code> is a field-based time point with a resolution of days, except that it is restricted to pointing to the last day of a year and month. The class supports years- and months-oriented arithmetic, but not days-oriented arithmetic.</td> </tr> <tr> <td><code>year_month_weekday</code></td> <td>represents a specific year, month, and n-th weekday of the month. <code>year_month_weekday</code> is a field-based time point with a resolution of days. The class supports years- and months-oriented arithmetic, but not days-oriented arithmetic.</td> </tr> <tr> <td><code>year_month_weekday_last</code></td> <td>represents a specific year, month, and last weekday of the month. <code>year_month_weekday_last</code> is a field-based time point with a resolution of days, except that it is restricted to pointing to the last weekday of a year and month. The class supports years- and months-oriented arithmetic, but not days-oriented arithmetic.</td> </tr> </tbody> </table> <p>And some notes:</p> <ul> <li>All above classes, except of <code>last_spec</code>, are trivially copyable and standard-layout class types.</li> <li>Most types have the <code>ok()</code> member function that returns true if a given state is correct in terms of the type, or its subtypes.</li> <li>They have an implicit <code>constexpr</code> constructor from <code>sys_days</code> and an explicit <code>constexpr</code> constructor from <code>local_days</code> for days-oriented arithmetic.</li> <li>Notice that duration types end with <code>s</code>, while calendrical types have a singular form, like <code>day</code>, <code>month</code>, etc.</li> </ul> <h2 id="constants"> Constants <a class="hash-link" href="#constants" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Inside the <code>std::chrono</code> namespace, we also have the following calendrical constants:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">last_spec</span> <span class="n">last</span><span class="p">{};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">weekday</span> <span class="n">Sunday</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">weekday</span> <span class="n">Monday</span><span class="p">{</span><span class="mi">1</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">weekday</span> <span class="n">Tuesday</span><span class="p">{</span><span class="mi">2</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">weekday</span> <span class="n">Wednesday</span><span class="p">{</span><span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">weekday</span> <span class="n">Thursday</span><span class="p">{</span><span class="mi">4</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">weekday</span> <span class="n">Friday</span><span class="p">{</span><span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">weekday</span> <span class="n">Saturday</span><span class="p">{</span><span class="mi">6</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">January</span><span class="p">{</span><span class="mi">1</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">February</span><span class="p">{</span><span class="mi">2</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">March</span><span class="p">{</span><span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">April</span><span class="p">{</span><span class="mi">4</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">May</span><span class="p">{</span><span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">June</span><span class="p">{</span><span class="mi">6</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">July</span><span class="p">{</span><span class="mi">7</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">August</span><span class="p">{</span><span class="mi">8</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">September</span><span class="p">{</span><span class="mi">9</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">October</span><span class="p">{</span><span class="mi">10</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">November</span><span class="p">{</span><span class="mi">11</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">month</span> <span class="n">December</span><span class="p">{</span><span class="mi">12</span><span class="p">};</span> </span></span></code></pre></div><h2 id="creation-and-operator-"> Creation and Operator <code>/</code> <a class="hash-link" href="#creation-and-operator-" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Constructors of chrono date types taking an integral value are explicit, so that copy initialization with an integral won&rsquo;t work:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span> <span class="n">d</span><span class="p">{</span><span class="mi">7</span><span class="p">};</span> <span class="c1">// OK </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span> <span class="n">anotherDay</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">// ERROR </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span> <span class="n">m</span><span class="p">{</span><span class="mi">12</span><span class="p">};</span> <span class="c1">// OK </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span> <span class="n">anotherMonth</span> <span class="o">=</span> <span class="mi">12</span><span class="p">;</span> <span class="c1">// ERROR </span></span></span></code></pre></div><p><code>std::chrono</code> exposes 40 overloads for the operator <code>/</code>, allowing us to create various calendar types with many combinations easily. Usually, you only have to provide the first type, and then the compiler will deduce the further sequence.</p> <p>For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">ymdOct</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span> <span class="p">{</span> <span class="mi">1996</span> <span class="p">}</span> <span class="o">/</span> <span class="mi">10</span> <span class="o">/</span> <span class="mi">31</span><span class="p">;</span> <span class="c1">// 31st october 1996, year_month_day </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">ydmOct</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span> <span class="p">{</span> <span class="mi">1996</span> <span class="p">}</span> <span class="o">/</span> <span class="mi">31</span> <span class="o">/</span> <span class="mi">10</span><span class="p">;</span> <span class="c1">// yyyy/dd/mm not possible, so this yields an invalid date! </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">ym</span> <span class="p">{</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="p">{</span><span class="mi">2025</span><span class="p">}</span> <span class="o">/</span> <span class="mi">11</span><span class="p">};</span> <span class="c1">// year_month </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">mw</span> <span class="p">{</span><span class="mi">11</span><span class="o">/</span><span class="n">Monday</span><span class="p">[</span><span class="mi">3</span><span class="p">]};</span> <span class="c1">// 3rd Monday in Nov, month_weekday </span></span></span></code></pre></div><h3 id="literals"> Literals <a class="hash-link" href="#literals" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>As Howard Hinnant pointed out in <a href="https://github.com/fenbf/cppstories-discussions/issues/162#issuecomment-3592169381">the comment</a> - there&rsquo;s even easier way to specify dates - using literals.</p> <p>For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span> <span class="n">today</span><span class="p">{</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="p">{</span><span class="mi">2025</span><span class="p">}</span><span class="o">/</span><span class="mi">11</span><span class="o">/</span><span class="mi">22</span> <span class="p">};</span> </span></span></code></pre></div><p>can be written as:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">literals</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">today</span> <span class="o">=</span> <span class="mi">2025</span><span class="n">y</span><span class="o">/</span><span class="mi">11</span><span class="o">/</span><span class="mi">22</span><span class="p">;</span> </span></span></code></pre></div><p>We have the following literals:</p> <table> <thead> <tr> <th>Literal</th> <th>Notes</th> </tr> </thead> <tbody> <tr> <td><code>operator&quot;&quot;h</code></td> <td><code>std::chrono::duration</code> literal representing hours (C++14)</td> </tr> <tr> <td><code>operator&quot;&quot;min</code></td> <td><code>std::chrono::duration</code> literal representing minutes (C++14)</td> </tr> <tr> <td><code>operator&quot;&quot;s</code></td> <td><code>std::chrono::duration</code> literal representing seconds (C++14)</td> </tr> <tr> <td><code>operator&quot;&quot;ms</code></td> <td><code>std::chrono::duration</code> literal representing milliseconds (C++14)</td> </tr> <tr> <td><code>operator&quot;&quot;us</code></td> <td><code>std::chrono::duration</code> literal representing microseconds (C++14)</td> </tr> <tr> <td><code>operator&quot;&quot;ns</code></td> <td><code>std::chrono::duration</code> literal representing nanoseconds (C++14)</td> </tr> <tr> <td><code>operator&quot;&quot;d</code></td> <td><code>std::chrono::day</code> literal representing a day of a month (C++20)</td> </tr> <tr> <td><code>operator&quot;&quot;y</code></td> <td><code>std::chrono::year</code> literal representing a particular year (C++20)</td> </tr> </tbody> </table> <p>See the example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono_literals</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="mi">2025</span><span class="n">y</span><span class="o">/</span><span class="n">June</span><span class="o">/</span><span class="mi">30</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="mi">2025</span><span class="n">y</span><span class="o">/</span><span class="mi">1</span><span class="o">/</span><span class="mi">30</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="mi">2026</span><span class="n">y</span><span class="o">/</span><span class="n">January</span><span class="o">/</span><span class="mi">1</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/PxzEWann3">@Compiler Explorer</a></p> <h2 id="validating-dates"> Validating Dates <a class="hash-link" href="#validating-dates" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Calendar types allow invalid states by design. That makes them cheap, <code>constexpr</code>-friendly value types, but it also means validation is explicit.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> </span></span><span class="line"><span class="cl"><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">year_month_day</span> <span class="n">ymd1</span><span class="p">{</span> <span class="n">year</span><span class="p">{</span><span class="mi">2025</span><span class="p">}</span> <span class="o">/</span> <span class="n">February</span> <span class="o">/</span> <span class="mi">29</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">year_month_day</span> <span class="n">ymd2</span><span class="p">{</span> <span class="n">year</span><span class="p">{</span><span class="mi">2024</span><span class="p">}</span> <span class="o">/</span> <span class="n">February</span> <span class="o">/</span> <span class="mi">29</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{:%D} ok: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ymd1</span><span class="p">,</span> <span class="n">ymd1</span><span class="p">.</span><span class="n">ok</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} ok: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ymd1</span><span class="p">,</span> <span class="n">ymd1</span><span class="p">.</span><span class="n">ok</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{:%D} ok: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ymd2</span><span class="p">,</span> <span class="n">ymd2</span><span class="p">.</span><span class="n">ok</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/9YTvd6WsM">@Compiler Explorer</a></p> <p>Output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">02/29/25 ok: false </span></span><span class="line"><span class="cl">2025-02-29 is not a valid date ok: false </span></span><span class="line"><span class="cl">02/29/24 ok: true </span></span></code></pre></div><p>The interesting part is that when printing a date with default formatter it can add extra text when the date is invalid. This is not the case with <code>:%D</code> specifier.</p> <h2 id="arithmetic"> Arithmetic <a class="hash-link" href="#arithmetic" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Some useful operations for working with calendrical types:</p> <h3 id="day"> <code>day</code> <a class="hash-link" href="#day" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// member functions: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">+=</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="o">&amp;</span> <span class="n">d</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">-=</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="o">&amp;</span> <span class="n">d</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// non-member: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span><span class="o">&amp;</span> <span class="n">d</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="o">&amp;</span> <span class="n">ds</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="o">&amp;</span> <span class="n">ds</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span><span class="o">&amp;</span> <span class="n">d</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span> <span class="k">operator</span><span class="o">-</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span><span class="o">&amp;</span> <span class="n">d</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="o">&amp;</span> <span class="n">ds</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="c1">// notice it returns `days`, not `day`: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span> <span class="k">operator</span><span class="o">-</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span><span class="o">&amp;</span> <span class="n">y</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span></code></pre></div><p>Operators: <code>++</code> and <code>--</code> are also supported.</p> <p>Examples:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> </span></span><span class="line"><span class="cl"><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span> <span class="n">oneDay</span><span class="p">{</span> <span class="mi">7</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span> <span class="n">anotherDay</span><span class="p">{</span> <span class="mi">30</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">oneDay</span> <span class="o">+=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="p">(</span><span class="mi">20</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;7 + 20: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">oneDay</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">day</span> <span class="n">future</span> <span class="o">=</span> <span class="n">anotherDay</span> <span class="o">+</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="p">{</span> <span class="mi">10</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;oneDay + anotherDay: {}, ok: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">future</span><span class="p">,</span> <span class="n">future</span><span class="p">.</span><span class="n">ok</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span> <span class="n">res</span> <span class="o">=</span> <span class="n">oneDay</span> <span class="o">-</span> <span class="n">anotherDay</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;res: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">res</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/Md81nKv1z">@Compiler Explorer</a></p> <p>The output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">7 + 20: 27 </span></span><span class="line"><span class="cl">oneDay + anotherDay: 40 is not a valid day, ok: false </span></span><span class="line"><span class="cl">res: -3d </span></span></code></pre></div><p>Notice the type difference for the <code>-</code> operator. It&rsquo;s <code>days</code>.</p> <h3 id="month"> <code>month</code> <a class="hash-link" href="#month" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// member operations: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">+=</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="o">&amp;</span> <span class="n">m</span><span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">+=</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="o">&amp;</span> <span class="n">m</span><span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// non member: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span><span class="o">&amp;</span> <span class="n">m</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="o">&amp;</span> <span class="n">ms</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="o">&amp;</span> <span class="n">ms</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span><span class="o">&amp;</span> <span class="n">m</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span> <span class="k">operator</span><span class="o">-</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span><span class="o">&amp;</span> <span class="n">m</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="o">&amp;</span> <span class="n">ms</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// type change here: `months`! </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span> <span class="k">operator</span><span class="o">-</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span><span class="o">&amp;</span> <span class="n">m1</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span><span class="o">&amp;</span> <span class="n">m2</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span></code></pre></div><p>Operators: <code>++</code> and <code>--</code> are also supported.</p> <p>The set of operations is similar to <code>day</code>.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span> <span class="n">oneMonth</span><span class="p">{</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">September</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">oneMonth</span> <span class="o">+=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="p">(</span><span class="mi">20</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Sept + 20 months: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">oneMonth</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">month</span> <span class="n">future</span> <span class="o">=</span> <span class="n">oneMonth</span> <span class="o">+</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="p">{</span> <span class="mi">10</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;oneMonth + months(10): {}, ok: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">future</span><span class="p">,</span> <span class="n">future</span><span class="p">.</span><span class="n">ok</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span> <span class="n">res</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">March</span> <span class="o">-</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">January</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Mar - Jan: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">res</span><span class="p">);</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/nPjTasE6x">@Compiler Explorer</a></p> <p>The output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Sept + 20 months: May </span></span><span class="line"><span class="cl">oneMonth + months(10): Mar, ok: true </span></span><span class="line"><span class="cl">Mar - Jan: 2[2629746]s </span></span></code></pre></div><h3 id="year"> <code>year</code> <a class="hash-link" href="#year" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// member functions: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">+=</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="o">&amp;</span> <span class="n">y</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">-=</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="o">&amp;</span> <span class="n">y</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span> <span class="k">operator</span><span class="o">+</span><span class="p">()</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span> <span class="k">operator</span><span class="o">-</span><span class="p">()</span> <span class="k">noexcept</span><span class="p">;</span> <span class="c1">// negation! </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"><span class="c1">// non-member functions: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="o">&amp;</span> <span class="n">y</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="o">&amp;</span> <span class="n">ys</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="o">&amp;</span> <span class="n">ys</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="o">&amp;</span> <span class="n">y</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span> <span class="k">operator</span><span class="o">-</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="o">&amp;</span> <span class="n">y</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="o">&amp;</span> <span class="n">ys</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// type change: years </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span> <span class="k">operator</span><span class="o">-</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="o">&amp;</span> <span class="n">y1</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="o">&amp;</span> <span class="n">y2</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span></code></pre></div><p>Operators: <code>++</code> and <code>--</code> are also supported.</p> <p>See a basic example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span> <span class="n">xxiCentury</span><span class="p">{</span> <span class="mi">2001</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">xxiCentury</span> <span class="o">+=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="p">{</span> <span class="mi">21</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;2001 + 21 years: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">xxiCentury</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;min {}, max {} year</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="o">::</span><span class="n">min</span><span class="p">(),</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="o">::</span><span class="n">max</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span> <span class="n">future</span> <span class="o">=</span> <span class="n">xxiCentury</span> <span class="o">+</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="p">{</span> <span class="mi">100000</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;xxiCentury + years(100000): {}, ok: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">future</span><span class="p">,</span> <span class="n">future</span><span class="p">.</span><span class="n">ok</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span> <span class="n">res</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="p">{</span> <span class="mi">2022</span> <span class="p">}</span> <span class="o">-</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="p">{</span> <span class="mi">22</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Mar - Jan: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">res</span><span class="p">);</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/q4vYMG9er">@Compiler Explorer</a></p> <p>The output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">2001 + 21 years: 2022 </span></span><span class="line"><span class="cl">min -32767, max 32767 year </span></span><span class="line"><span class="cl">xxiCentury + years(100000): -29050, ok: true </span></span><span class="line"><span class="cl">Mar - Jan: 2000[31556952]s </span></span></code></pre></div><h3 id="year_month_day"> <code>year_month_day</code> <a class="hash-link" href="#year_month_day" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>This structure is a pack of <code>year</code>, <code>month</code> and <code>day</code> structures, but it exposes the following arithmetic operations:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// member functions: </span></span></span><span class="line"><span class="cl"><span class="c1">// you can add/subtract only months or years </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span><span class="o">&amp;</span> </span></span><span class="line"><span class="cl"> <span class="k">operator</span><span class="o">+=</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="o">&amp;</span> <span class="n">dy</span> <span class="p">)</span> <span class="k">const</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span><span class="o">&amp;</span> </span></span><span class="line"><span class="cl"> <span class="k">operator</span><span class="o">+=</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="o">&amp;</span> <span class="n">dm</span> <span class="p">)</span> <span class="k">const</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span><span class="o">&amp;</span> </span></span><span class="line"><span class="cl"> <span class="k">operator</span><span class="o">-=</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="o">&amp;</span> <span class="n">dy</span> <span class="p">)</span> <span class="k">const</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span><span class="o">&amp;</span> </span></span><span class="line"><span class="cl"> <span class="k">operator</span><span class="o">-=</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="o">&amp;</span> <span class="n">dm</span> <span class="p">)</span> <span class="k">const</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// non-member functions: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span><span class="o">&amp;</span> <span class="n">ymd</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="o">&amp;</span> <span class="n">dm</span><span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="o">&amp;</span> <span class="n">dm</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span><span class="o">&amp;</span> <span class="n">ymd</span><span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span><span class="o">&amp;</span> <span class="n">ymd</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="o">&amp;</span> <span class="n">dy</span><span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="o">&amp;</span> <span class="n">dy</span><span class="p">,</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span><span class="o">&amp;</span> <span class="n">ymd</span><span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span> <span class="k">operator</span><span class="o">-</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span><span class="o">&amp;</span> <span class="n">ymd</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="o">&amp;</span> <span class="n">dm</span><span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span> <span class="k">operator</span><span class="o">-</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span><span class="o">&amp;</span> <span class="n">ymd</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="o">&amp;</span> <span class="n">dy</span><span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span></code></pre></div><p>This time, we can only add/subtract <code>years</code> or <code>months</code>, and there&rsquo;s no operation that returns some duration type.</p> <p>See an example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span> <span class="n">today</span><span class="p">{</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="p">{</span><span class="mi">2025</span><span class="p">}</span><span class="o">/</span><span class="mi">11</span><span class="o">/</span><span class="mi">22</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">future</span> <span class="o">=</span> <span class="n">today</span> <span class="o">+</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">years</span><span class="p">{</span> <span class="mi">10</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;2025/11/22 + 10 years: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">future</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year_month_day</span> <span class="n">again</span> <span class="o">=</span> <span class="n">future</span> <span class="o">-</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">months</span><span class="p">{</span> <span class="mi">120</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;future - months(120): {}, ok: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">again</span><span class="p">,</span> <span class="n">again</span><span class="p">.</span><span class="n">ok</span><span class="p">());</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/on8rK3Td5">@Compiler Explorer</a></p> <p>The output</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">2025/11/22 + 10 years: 2035-11-22 </span></span><span class="line"><span class="cl">future - months(120): 2025-11-22, ok: true </span></span></code></pre></div><h3 id="weekday"> <code>weekday</code> <a class="hash-link" href="#weekday" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// member functions: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">weekday</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">+=</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="o">&amp;</span> <span class="n">d</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">weekday</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">-=</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="o">&amp;</span> <span class="n">d</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// non-member functions: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">weekday</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">weekday</span><span class="o">&amp;</span> <span class="n">wd</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="o">&amp;</span> <span class="n">d</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">weekday</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="o">&amp;</span> <span class="n">d</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">weekday</span><span class="o">&amp;</span> <span class="n">wd</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">weekday</span> <span class="k">operator</span><span class="o">-</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">weekday</span><span class="o">&amp;</span> <span class="n">wd</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="o">&amp;</span> <span class="n">d</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="c1">// return type change to days: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span> <span class="k">operator</span><span class="o">-</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">weekday</span><span class="o">&amp;</span> <span class="n">wd1</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">weekday</span><span class="o">&amp;</span> <span class="n">wd2</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span></code></pre></div><p>We can operate with <code>days</code> and also two <code>weekdays</code>. The types use modulo arithmetic.</p> <p>See the example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">weekday</span> <span class="n">aday</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">Sunday</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">aday</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="o">++</span><span class="n">aday</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">aday</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">aday</span> <span class="o">+=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">days</span><span class="p">{</span> <span class="mi">22</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;after adding 22 days: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">aday</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Monday - Tuesday = {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">Monday</span> <span class="o">-</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">Tuesday</span><span class="p">);</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/s95vcMdz4">@Compiler Explorer</a></p> <p>The output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Sun </span></span><span class="line"><span class="cl">Mon </span></span><span class="line"><span class="cl">after adding 22 days: Tue </span></span><span class="line"><span class="cl">Monday - Tuesday = 6d </span></span></code></pre></div><h2 id="days-arithmetic-for-year_-and-month_-types"> Days arithmetic for <code>year_*</code> and <code>month_*</code> types <a class="hash-link" href="#days-arithmetic-for-year_-and-month_-types" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>As you saw in the table, types for years and months support month/year arithmetic:</p> <blockquote> <p>The class supports years- and months-oriented arithmetic, but not days-oriented arithmetic. For the latter, there is a conversion to <code>sys_days</code>, which efficiently supports days-oriented arithmetic.</p> </blockquote> <p>But in most cases, we can easily convert to <code>sys_days</code>, perform the computations, and convert back to the desired type.</p> <p>For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="n">chr</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">auto</span> <span class="n">today</span> <span class="o">=</span> <span class="n">chr</span><span class="o">::</span><span class="n">sys_days</span><span class="p">{</span> <span class="n">chr</span><span class="o">::</span><span class="n">floor</span><span class="o">&lt;</span><span class="n">chr</span><span class="o">::</span><span class="n">days</span><span class="o">&gt;</span><span class="p">(</span><span class="n">chr</span><span class="o">::</span><span class="n">system_clock</span><span class="o">::</span><span class="n">now</span><span class="p">())</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">importantDate</span> <span class="o">=</span> <span class="n">chr</span><span class="o">::</span><span class="n">year</span><span class="p">{</span> <span class="mi">2011</span> <span class="p">}</span> <span class="o">/</span> <span class="n">chr</span><span class="o">::</span><span class="n">July</span> <span class="o">/</span> <span class="mi">21</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">auto</span> <span class="n">delta</span> <span class="o">=</span> <span class="p">(</span><span class="n">today</span> <span class="o">-</span> <span class="n">chr</span><span class="o">::</span><span class="n">sys_days</span><span class="p">{</span> <span class="n">importantDate</span> <span class="p">}).</span><span class="n">count</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} was {} days ago!</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">importantDate</span><span class="p">,</span> <span class="n">delta</span><span class="p">);</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/sbosqxGa9">@Compiler Explorer</a></p> <p>The output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">2011-07-21 was 5238 days ago! </span></span></code></pre></div><p>PS: Do you know what significant event happened on that important date? (hint: something with space exploration).</p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>C++20 significantly enhances <code>&lt;chrono&gt;</code> with a comprehensive set of calendar types - such as <code>day</code>, <code>month</code>, <code>year</code>, <code>weekday</code>, and <code>year_month_day</code>- that let you represent and manipulate civil dates in a clear, type-safe way. These types support convenient construction via the <code>/</code> operator, simple month/year arithmetic, validation with <code>.ok()</code>, and easy conversion to <code>sys_days</code> whenever day-precision logic is needed.</p> <p>Next time, we&rsquo;ll look at more examples of calendar types.</p> <h2 id="documents-and-resources"> Documents and Resources <a class="hash-link" href="#documents-and-resources" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li><a href="https://timsong-cpp.github.io/cppwp/n4868/time">C++ Standard Draft - Time section</a> - N4868 (October 2020 pre-virtual-plenary working draft/C++20 plus editorial changes)</li> <li><a href="https://amzn.to/4huhBwt">C++20 - The Complete Guide by Nicolai M. Josuttis</a> @Amazon</li> <li><a href="https://amzn.to/48OaFI9">Modern C++ Programming Cookbook: Master C++ core language and standard library features, with over 100 recipes, updated to C++20 2nd ed. Edition</a> @Amazon</li> <li><a href="https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes">https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes</a> - examples and recipes for Howard Hinnant&rsquo;s <code>tz.h</code> library, which is a base for chrono.</li> </ul> C++ Templates: How to Iterate through std::tuple: C++26 Packs and Expansion Statements https://www.cppstories.com/2025/tuple-iteration-cpp26/ Sun, 12 Oct 2025 00:00:00 +0000 https://www.cppstories.com/2025/tuple-iteration-cpp26/ <p>In <a href="https://www.cppstories.com/2022/tuple-iteration-basics/">part 1</a> of this mini-series, we looked at the basics of iterating over a <code>std::tuple</code> using <code>index_sequence</code> and fold expressions. In <a href="https://www.cppstories.com/2022/tuple-iteration-apply/">part 2</a>, we simplified things with <code>std::apply</code> and even created helpers like <code>for_each_tuple</code> and <code>transform_tuple</code>.</p> <p>So far, we used C++ features up to C++20/23&hellip; but now, in C++26, we finally get language-level tools that make tuple iteration straightforward and expressive. In this article, we’ll explore two new techniques:</p> <ul> <li>Structured bindings can introduce a pack - <a href="https://wg21.link/P1061R10">P1061</a> - turn a tuple into a pack of variables.</li> <li>Expansion statements <a href="https://wg21.link/p1306">P1306</a> - the ultimate “compile-time loop” syntax.</li> </ul> <h2 id="structured-binding-packs"> Structured binding packs <a class="hash-link" href="#structured-binding-packs" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Structured bindings have been around since C++17, but in C++26 they gained the ability to introduce packs. That means you can bind an arbitrary number of elements without spelling each out.</p> <p>For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="p">[</span><span class="n">head</span><span class="p">,</span> <span class="p">...</span><span class="n">rest</span><span class="p">]</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="c1">// head == 1, rest... expands to (2, 3, 4) </span></span></span></code></pre></div><p>This feature gives us a way to expand tuples into parameter packs, and once we have a pack, we can use fold expressions and other familiar template techniques.</p> <h3 id="printing-a-tuple"> Printing a tuple <a class="hash-link" href="#printing-a-tuple" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>We can bind all elements of a tuple into a pack and then fold over it:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;tuple&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;utility&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Tuple</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">print_tuple</span><span class="p">(</span><span class="k">const</span> <span class="n">Tuple</span><span class="o">&amp;</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[...</span><span class="n">xs</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="kt">bool</span> <span class="n">first</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;(&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">((</span><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exchange</span><span class="p">(</span><span class="n">first</span><span class="p">,</span> <span class="nb">false</span><span class="p">)</span> <span class="o">?</span> <span class="s">&#34;&#34;</span> <span class="o">:</span> <span class="s">&#34;, &#34;</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">xs</span><span class="p">),</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">print_tuple</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">make_tuple</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mf">2.2</span><span class="p">,</span> <span class="s">&#34;hello&#34;</span><span class="p">));</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See at <a href="https://godbolt.org/z/xqeveGWYq">Compiler Explorer</a></p> <p>This is a direct replacement for our old <code>index_sequence</code> or <code>std::apply</code> approaches - now written in plain C++26.</p> <p>(Of course, you can easily update it to work with <code>std::print</code>)</p> <h3 id="transforming-a-tuple"> Transforming a tuple <a class="hash-link" href="#transforming-a-tuple" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>We can also apply a transformation and create a new tuple:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Tuple</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Fn</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">transform_tuple</span><span class="p">(</span><span class="k">const</span> <span class="n">Tuple</span><span class="o">&amp;</span> <span class="n">t</span><span class="p">,</span> <span class="n">Fn</span><span class="o">&amp;&amp;</span> <span class="n">fn</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[...</span><span class="n">xs</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">make_tuple</span><span class="p">(</span><span class="n">fn</span><span class="p">(</span><span class="n">xs</span><span class="p">)...);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">tuple</span> <span class="n">tp</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">doubled</span> <span class="o">=</span> <span class="n">transform_tuple</span><span class="p">(</span><span class="n">tp</span><span class="p">,</span> <span class="p">[](</span><span class="k">auto</span> <span class="n">x</span><span class="p">){</span> <span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> <span class="p">});</span> </span></span><span class="line"><span class="cl"><span class="c1">// doubled == (2, 4, 6) </span></span></span></code></pre></div><p>See <a href="https://godbolt.org/z/7br17711W">@Compiler Explorer</a></p> <p>Here the <code>...xs</code> pack is expanded inside <code>std::make_tuple</code>. This is exactly like writing <code>fn(x1), fn(x2), fn(x3)</code>, but without the boilerplate.</p> <h3 id="dot-product"> Dot product <a class="hash-link" href="#dot-product" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>And another example, taken from the proposal:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span> <span class="nc">P</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Q</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="k">auto</span> <span class="n">dot_product</span><span class="p">(</span><span class="k">const</span> <span class="n">P</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">,</span> <span class="k">const</span> <span class="n">Q</span><span class="o">&amp;</span> <span class="n">q</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[...</span><span class="n">ps</span><span class="p">]</span> <span class="o">=</span> <span class="n">p</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[...</span><span class="n">qs</span><span class="p">]</span> <span class="o">=</span> <span class="n">q</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="k">sizeof</span><span class="p">...(</span><span class="n">ps</span><span class="p">)</span> <span class="o">==</span> <span class="k">sizeof</span><span class="p">...(</span><span class="n">qs</span><span class="p">),</span> <span class="s">&#34;Mismatched sizes&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">((</span><span class="n">ps</span> <span class="o">*</span> <span class="n">qs</span><span class="p">)</span> <span class="o">+</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">3</span><span class="o">&gt;</span> <span class="n">a</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">3</span><span class="o">&gt;</span> <span class="n">b</span><span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">static_assert</span><span class="p">(</span><span class="n">dot_product</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="o">==</span> <span class="mi">32</span><span class="p">);</span> </span></span></code></pre></div><p>Here’s the link to <a href="https://godbolt.org/z/5hWTE8YdY">Compiler Explorer</a></p> <p>With structured binding packs, tuples and arrays become much more convenient to manipulate.</p> <h2 id="expansion-statements"> Expansion statements <a class="hash-link" href="#expansion-statements" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>While structured binding packs let us turn tuples into packs of variables, <strong>expansion statements</strong> go even further: they let us write a compile-time loop <em>directly in the language</em>.</p> <p>In short, you can now write:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="nf">for</span> <span class="p">(...)</span> <span class="p">{</span> <span class="p">}</span> </span></span></code></pre></div><p>See this:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">tp</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_tuple</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mf">3.14</span><span class="p">,</span> <span class="s">&#34;hello&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;(&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="kt">bool</span> <span class="n">first</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="nf">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">e</span> <span class="p">:</span> <span class="n">tp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">std</span><span class="o">::</span><span class="n">exchange</span><span class="p">(</span><span class="n">first</span><span class="p">,</span> <span class="nb">false</span><span class="p">))</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)&#34;</span><span class="p">;</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/GTqM5jh9q">@Compiler Explorer</a></p> <p>No <code>index_sequence</code>, no <code>std::get</code>, no <code>std::apply</code>. Just a clean <code>template for</code>!</p> <h3 id="transforming-tuples"> Transforming tuples <a class="hash-link" href="#transforming-tuples" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>We can also transform the tuple:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;tuple&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;utility&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span> <span class="nc">Tuple</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">print_tuple_expand</span><span class="p">(</span><span class="k">const</span> <span class="n">Tuple</span><span class="o">&amp;</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">bool</span> <span class="n">first</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;(&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">template</span> <span class="nf">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">e</span> <span class="p">:</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">std</span><span class="o">::</span><span class="n">exchange</span><span class="p">(</span><span class="n">first</span><span class="p">,</span> <span class="nb">false</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;, &#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{}&#34;</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span> <span class="nc">Tuple</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Fn</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">for_each_tuple_expand</span><span class="p">(</span><span class="n">Tuple</span><span class="o">&amp;&amp;</span> <span class="n">t</span><span class="p">,</span> <span class="n">Fn</span><span class="o">&amp;&amp;</span> <span class="n">fn</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">template</span> <span class="nf">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="nl">e</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Tuple</span><span class="o">&gt;</span><span class="p">(</span><span class="n">t</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">fn</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">&gt;</span><span class="p">(</span><span class="n">e</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">tp</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_tuple</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mf">3.14</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">print_tuple_expand</span><span class="p">(</span><span class="n">tp</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">for_each_tuple_expand</span><span class="p">(</span><span class="n">tp</span><span class="p">,</span> <span class="p">[](</span><span class="k">auto</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span><span class="n">x</span> <span class="o">*=</span> <span class="mi">2</span><span class="p">;});</span> </span></span><span class="line"><span class="cl"> <span class="n">print_tuple_expand</span><span class="p">(</span><span class="n">tp</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/e1veeqvvM">@Compiler Explorer</a></p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>This article closes the mini-series about tuple iteration. It&rsquo;s great to see that over the years, C++ has evolved in a way that template/meta programming looks almost the same as regular runtime code. In the first installments of this series, I showed you some tricks, like integer sequence, std::apply&hellip; but in C++26, we can remove them and take advantage of <code>template for</code>.</p> <p>(Of course, it&rsquo;s still good to know the tricks up to C++23&hellip; as C++26 won&rsquo;t be used in production for a couple more years :))</p> <ul> <li>See the part one here: <a href="https://www.cppstories.com/2022/tuple-iteration-basics/">C++ Templates: How to Iterate through std::tuple: the Basics - C++ Stories</a>.</li> <li>See the second part here: <a href="https://www.cppstories.com/2022/tuple-iteration-apply/">C++ Templates: How to Iterate through std::tuple: std::apply and More - C++ Stories</a></li> </ul> <h4 id="references"> References: </h4> <ul> <li><a href="https://amzn.to/3GMx8Uu">Effective Modern C++</a> by Scott Meyers</li> <li><a href="http://amzn.to/2wtoENU">C++ Templates: The Complete Guide (2nd Edition)</a> by David Vandevoorde, Nicolai M. Josuttis, Douglas Gregor</li> </ul> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Do you use std::apply in your code, or do you prefer some manual techniques?</li> <li>Do you see other benefits of using <code>template for</code>?</li> </ul> <p>Share your feedback in the comments below.</p> C++ Templates: How to Iterate through std::tuple: std::apply and More https://www.cppstories.com/2022/tuple-iteration-apply/ Sun, 21 Sep 2025 00:00:00 +0000 https://www.cppstories.com/2022/tuple-iteration-apply/ <p>In the previous article on the tuple iteration, we covered the basics. As a result, we implemented a function template that took a tuple and could nicely print it to the output. There was also a version with <code>operator &lt;&lt;</code>.</p> <p>Today we can go further and see some other techniques. The first one is with <code>std::apply</code> from C++17, a helper function for tuples. Today&rsquo;s article will also cover some strategies to make the iteration more generic and handle custom callable objects, not just printing.</p> <blockquote class="hint note"> <p>This is the second part of the small series. See the first article <a href="https://www.cppstories.com/2022/tuple-iteration-basics/">here</a> where we discuss the basics.</p> <p>And see the <a href="https://www.cppstories.com/2025/tuple-iteration-cpp26/">third part</a> about the ultimate solution with C++26.</p> </blockquote> <blockquote class="hint info"> Updated in Sept 2025: Extended the &ldquo;Return value&rdquo; section. </blockquote> <h2 id="stdapply-approach"> std:apply approach <a class="hash-link" href="#stdapply-approach" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>A handy helper for <code>std::tuple</code> is the <code>std::apply</code> function template that came in C++17. It takes a tuple and a callable object and then invokes this callable with parameters fetched from the tuple.</p> <p>Here&rsquo;s an example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;tuple&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">sum</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">,</span> <span class="kt">int</span> <span class="n">c</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="o">+</span> <span class="n">c</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">print</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">a</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;(&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">a</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">b</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span> <span class="n">numbers</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">apply</span><span class="p">(</span><span class="n">sum</span><span class="p">,</span> <span class="n">numbers</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span> <span class="n">strs</span> <span class="p">{</span><span class="s">&#34;Hello&#34;</span><span class="p">,</span> <span class="s">&#34;World&#34;</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">apply</span><span class="p">(</span><span class="n">print</span><span class="p">,</span> <span class="n">strs</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/vvc8fPTxx">@Compiler Explorer</a></p> <p>As you can see, <code>std::apply</code> takes <code>sum</code> or <code>print</code> functions and then &ldquo;expands&rdquo; tuples and calls those functions with appropriate arguments.</p> <p>Here&rsquo;s a diagram showing how it works:</p> <p><img src="../images/apply_diagram.png" alt=""></p> <p>Ok, but how does it relate to our problem?</p> <p>The critical thing is that <code>std::apply</code> hides all index generation and calls to <code>std::get&lt;&gt;</code>. That&rsquo;s why we can replace our printing function with <code>std::apply</code> and then don&rsquo;t use <code>index_sequence</code>.</p> <h3 id="the-first-approach---working"> The first approach - working? <a class="hash-link" href="#the-first-approach---working" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>The first approach that came to my mind was the following - create a variadic function template that takes <code>Args...</code> and pass it to <code>std::apply</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">printImpl</span><span class="p">(</span><span class="k">const</span> <span class="n">Args</span><span class="o">&amp;</span><span class="p">...</span> <span class="n">tupleArgs</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">printElem</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="n">index</span><span class="p">](</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">index</span><span class="o">++</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">x</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">printElem</span><span class="p">(</span><span class="n">tupleArgs</span><span class="p">),</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">printTupleApplyFn</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="o">&lt;</span><span class="n">Args</span><span class="p">...</span><span class="o">&gt;&amp;</span> <span class="n">tp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;(&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">apply</span><span class="p">(</span><span class="n">printImpl</span><span class="p">,</span> <span class="n">tp</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Looks&hellip; fine&hellip; right?</p> <p>The problem is that it doesn&rsquo;t compile :)</p> <p>GCC or Clang generates some general error which boils down to the following line:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">candidate template ignored: couldn&#39;t infer template argument &#39;_Fn </span></span></code></pre></div><p>But how? Why cannot the compiler get the proper template parameters for <code>printImpl</code>?</p> <p>The problem lies in the fact that out <code>printImpl</code> is a variadic function template, so the compiler has to instantiate it. The instantiation doesn&rsquo;t happen when we call <code>std::apply</code>, but inside <code>std::apply</code>. The compiler doesn&rsquo;t know how the callable object will be called when we call <code>std::apply</code>, so it cannot perform the template deduction at this stage.</p> <p>We can help the compiler and pass the arguments:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;tuple&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">printImpl</span><span class="p">(</span><span class="k">const</span> <span class="n">Args</span><span class="o">&amp;</span><span class="p">...</span> <span class="n">tupleArgs</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">printElem</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="n">index</span><span class="p">](</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">index</span><span class="o">++</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">x</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">printElem</span><span class="p">(</span><span class="n">tupleArgs</span><span class="p">),</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">printTupleApplyFn</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="o">&lt;</span><span class="n">Args</span><span class="p">...</span><span class="o">&gt;&amp;</span> <span class="n">tp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;(&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">apply</span><span class="p">(</span><span class="n">printImpl</span><span class="o">&lt;</span><span class="n">Args</span><span class="p">...</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">tp</span><span class="p">);</span> <span class="c1">// &lt;&lt; </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span> <span class="n">tp</span> <span class="p">{</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mf">3.14</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">printTupleApplyFn</span><span class="p">(</span><span class="n">tp</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/WTscsnvnz">@Compiler Explorer</a>.</p> <p>In the above example, we helped the compiler to create the requested instantiation, so it&rsquo;s happy to pass it to <code>std::apply</code>.</p> <p>But there&rsquo;s another technique we can do. How about helper callable type?</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">HelperCallable</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">Args</span><span class="o">&amp;</span><span class="p">...</span> <span class="n">tupleArgs</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">printElem</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="n">index</span><span class="p">](</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">index</span><span class="o">++</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">x</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">printElem</span><span class="p">(</span><span class="n">tupleArgs</span><span class="p">),</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">printTupleApplyFn</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="o">&lt;</span><span class="n">Args</span><span class="p">...</span><span class="o">&gt;&amp;</span> <span class="n">tp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;(&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">apply</span><span class="p">(</span><span class="n">HelperCallable</span><span class="p">(),</span> <span class="n">tp</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Can you see the difference?</p> <p>Now, what we do, we only pass a <code>HelperCallable</code> object; it&rsquo;s a concrete type so that the compiler can pass it without any issues. No template parameter deduction happens. And then, at some point, the compiler will call <code>HelperCallable(args...)</code>, which invokes <code>operator()</code> for that struct. And it&rsquo;s now perfectly fine, and the compiler can deduce the types. In other words, we deferred the problem.</p> <p>So we know that the code works fine with a helper callable type&hellip; so how about a lambda?</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;tuple&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">TupleT</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">printTupleApply</span><span class="p">(</span><span class="k">const</span> <span class="n">TupleT</span><span class="o">&amp;</span> <span class="n">tp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;(&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">apply</span><span class="p">([](</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span><span class="p">...</span> <span class="n">tupleArgs</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">printElem</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="n">index</span><span class="p">](</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">index</span><span class="o">++</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">x</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">printElem</span><span class="p">(</span><span class="n">tupleArgs</span><span class="p">),</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"> <span class="p">},</span> <span class="n">tp</span> </span></span><span class="line"><span class="cl"> <span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span> <span class="n">tp</span> <span class="p">{</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mf">3.14</span><span class="p">,</span> <span class="mi">42</span><span class="p">,</span> <span class="s">&#34;hello&#34;</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">printTupleApply</span><span class="p">(</span><span class="n">tp</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/xvvacxz8c">@Compiler Explorer</a>.</p> <p>Also works! I also simplified the template parameters to just <code>template &lt;typename TupleT&gt;</code>.</p> <p>As you can see, we have a lambda inside a lambda. It&rsquo;s similar to our custom type with <code>operator()</code>. You can also have a look at the transformation through C++ Insights: <a href="https://cppinsights.io/s/399f54bc">this link</a></p> <h3 id="printing-simplification"> Printing simplification <a class="hash-link" href="#printing-simplification" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Since our callable object gets a variadic argument list, we can use this information and make the code simpler.</p> <p>Thanks <a href="https://github.com/fenbf/cppstories-discussions/issues/75#issuecomment-1039487071">PiotrNycz</a> for pointing that out.</p> <p>The code inside the internal lambda uses <code>index</code> to check if we need to print the separator or not - it checks if we print the first argument. We can do this at compile-time:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;tuple&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">TupleT</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">printTupleApply</span><span class="p">(</span><span class="k">const</span> <span class="n">TupleT</span><span class="o">&amp;</span> <span class="n">tp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">apply</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="p">[](</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">first</span><span class="p">,</span> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span><span class="p">...</span> <span class="n">restArgs</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">printElem</span> <span class="o">=</span> <span class="p">[](</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">x</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;(&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">first</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">printElem</span><span class="p">(</span><span class="n">restArgs</span><span class="p">),</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"> <span class="p">},</span> <span class="n">tp</span> </span></span><span class="line"><span class="cl"> <span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span> <span class="n">tp</span> <span class="p">{</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mf">3.14</span><span class="p">,</span> <span class="mi">42</span><span class="p">,</span> <span class="s">&#34;hello&#34;</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">printTupleApply</span><span class="p">(</span><span class="n">tp</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/eMv718d9E">@Compiler Explorer</a>.</p> <p>This code breaks when tuple has no elements - we could fix this by checking its size in <code>if constexpr</code>, but let&rsquo;s skip it for now.</p> <div class="bonusWrapper"> <div class="bonusInfo"> <p> Would you like to <strong>see more?</strong> <br /> If you want to see a similar code that works with C++20's <code>std::format</code>, you can see my article: <a href="https://www.patreon.com/posts/61665073" target="_blank">How to format pairs and tuples with std::format (~1450 words)</a> which is available for <i>C++ Stories Premium/Patreon</i> members. See all <a href="https://www.cppstories.com/p/extra-patreon-content/">Premium benefits here</a>. </p> </div> </div> <h2 id="making-it-more-generic"> Making it more generic <a class="hash-link" href="#making-it-more-generic" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>So far we focused on printing tuple elements. So we had a &ldquo;fixed&rdquo; function that was called for each argument. To go further with our ideas, let&rsquo;s try to implement a function that takes a generic callable object. For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">tuple</span> <span class="n">tp</span> <span class="p">{</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mf">30.0</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">printTuple</span><span class="p">(</span><span class="n">tp</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">for_each_tuple</span><span class="p">(</span><span class="n">tp</span><span class="p">,</span> <span class="p">[](</span><span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">x</span><span class="p">){</span> </span></span><span class="line"><span class="cl"> <span class="n">x</span><span class="o">*=</span><span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">});</span> </span></span><span class="line"><span class="cl"><span class="n">printTuple</span><span class="p">(</span><span class="n">tp</span><span class="p">);</span> </span></span></code></pre></div><p>Let&rsquo;s start with the approach with index sequence:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">TupleT</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Fn</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">size_t</span><span class="p">...</span> <span class="n">Is</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">for_each_tuple_impl</span><span class="p">(</span><span class="n">TupleT</span><span class="o">&amp;&amp;</span> <span class="n">tp</span><span class="p">,</span> <span class="n">Fn</span><span class="o">&amp;&amp;</span> <span class="n">fn</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">index_sequence</span><span class="o">&lt;</span><span class="n">Is</span><span class="p">...</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">fn</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="n">Is</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">TupleT</span><span class="o">&gt;</span><span class="p">(</span><span class="n">tp</span><span class="p">))),</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">TupleT</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Fn</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">size_t</span> <span class="n">TupSize</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple_size_v</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">remove_cvref_t</span><span class="o">&lt;</span><span class="n">TupleT</span><span class="o">&gt;&gt;&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">for_each_tuple</span><span class="p">(</span><span class="n">TupleT</span><span class="o">&amp;&amp;</span> <span class="n">tp</span><span class="p">,</span> <span class="n">Fn</span><span class="o">&amp;&amp;</span> <span class="n">fn</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">for_each_tuple_impl</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">TupleT</span><span class="o">&gt;</span><span class="p">(</span><span class="n">tp</span><span class="p">),</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Fn</span><span class="o">&gt;</span><span class="p">(</span><span class="n">fn</span><span class="p">),</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">make_index_sequence</span><span class="o">&lt;</span><span class="n">TupSize</span><span class="o">&gt;</span><span class="p">{});</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>What happens here?</p> <p>First, the code uses universal references (forwarding references) to pass tuple objects. This is needed to support all kinds of use cases - especially if the caller wants to modify the values inside the tuple. That&rsquo;s why we need to use <code>std::forward</code> in all places.</p> <p>But why did I use <code>remove_cvref_t</code>?</p> <h2 id="on-stddecay-and-remove-ref"> On std::decay and remove ref <a class="hash-link" href="#on-stddecay-and-remove-ref" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>As you can see in my code I used:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">size_t</span> <span class="n">TupSize</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple_size_v</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">remove_cvref_t</span><span class="o">&lt;</span><span class="n">TupleT</span><span class="o">&gt;&gt;</span> </span></span></code></pre></div><p>This is a new helper type from the C++20 trait that makes sure we get a &ldquo;real&rdquo; type from the type we get through universal reference.</p> <p>Before C++20, you can often find <code>std::decay</code> used or <code>std::remove_reference</code>.</p> <p>Here&rsquo;s a good summary from a question about tuple iteration <a href="https://stackoverflow.com/questions/41199709/is-there-a-tuple-for-each-that-returns-a-tuple-of-all-values-returned-from-the/41200494?noredirect=1#comment125571672_41200494">link to Stackoverflow</a>:</p> <blockquote> <p>As <code>T&amp;&amp;</code> is a forwarding reference, <code>T</code> will be <code>tuple&lt;...&gt;&amp;</code> or <code>tuple&lt;...&gt; const&amp;</code> when an lvalue is passed in; but <code>std::tuple_size</code> is only specialized for <code>tuple&lt;...&gt;</code>, so we must strip off the reference and possible const. Prior to C++20&rsquo;s addition of <code>std::remove_cvref_t</code>, using <code>decay_t</code> was the easy (if overkill) solution.</p> </blockquote> <h2 id="generic-stdapply-version"> Generic <code>std::apply</code> version <a class="hash-link" href="#generic-stdapply-version" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>We discussed an implementation with index sequence; we can also try the same with std::apply. Can it yield simpler code?</p> <p>Here&rsquo;s my try:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">TupleT</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Fn</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">for_each_tuple2</span><span class="p">(</span><span class="n">TupleT</span><span class="o">&amp;&amp;</span> <span class="n">tp</span><span class="p">,</span> <span class="n">Fn</span><span class="o">&amp;&amp;</span> <span class="n">fn</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">apply</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="o">&amp;</span><span class="n">fn</span><span class="p">](</span><span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="p">...</span><span class="n">args</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">fn</span><span class="p">(</span><span class="n">args</span><span class="p">),</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"> <span class="p">},</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">TupleT</span><span class="o">&gt;</span><span class="p">(</span><span class="n">tp</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Look closer, I forgot to use <code>std::forward</code> when calling <code>fn</code>!</p> <p>We can solve this by using template lambdas available in C++20:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">TupleT</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Fn</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">for_each_tuple2</span><span class="p">(</span><span class="n">TupleT</span><span class="o">&amp;&amp;</span> <span class="n">tp</span><span class="p">,</span> <span class="n">Fn</span><span class="o">&amp;&amp;</span> <span class="n">fn</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">apply</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="o">&amp;</span><span class="n">fn</span><span class="p">]</span><span class="o">&lt;</span><span class="k">typename</span> <span class="p">...</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;&amp;</span> <span class="p">...</span><span class="n">args</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">fn</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">args</span><span class="p">)),</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"> <span class="p">},</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">TupleT</span><span class="o">&gt;</span><span class="p">(</span><span class="n">tp</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/jnTMxcEqn">@Compiler Explorer</a></p> <p>Additionally, if you want to stick to C++17, you can apply <code>decltype</code> on the arguments:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">TupleT</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Fn</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">for_each_tuple2</span><span class="p">(</span><span class="n">TupleT</span><span class="o">&amp;&amp;</span> <span class="n">tp</span><span class="p">,</span> <span class="n">Fn</span><span class="o">&amp;&amp;</span> <span class="n">fn</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">apply</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="o">&amp;</span><span class="n">fn</span><span class="p">](</span><span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="p">...</span><span class="n">args</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">fn</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="o">&gt;</span><span class="p">(</span><span class="n">args</span><span class="p">)),</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"> <span class="p">},</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">TupleT</span><span class="o">&gt;</span><span class="p">(</span><span class="n">tp</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play with code <a href="https://godbolt.org/z/rMehff8zo">@Compiler Explorer</a>.</p> <h2 id="return-value"> Return value <a class="hash-link" href="#return-value" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>So far, our <code>for_each_tuple</code> implementations focused on <strong>side effects</strong>: printing values, doubling them in place, etc. But what if you want to <strong>transform</strong> each element and collect the results into a new tuple, without modifying the original?</p> <p>For example, starting with:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">tuple</span> <span class="n">tp</span> <span class="p">{</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mf">30.0</span> <span class="p">};</span> </span></span></code></pre></div><p>we’d like to run a function on each element and get a <em>new tuple</em>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">res</span> <span class="o">=</span> <span class="n">transform_tuple</span><span class="p">(</span><span class="n">tp</span><span class="p">,</span> <span class="p">[](</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">){</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">});</span> </span></span></code></pre></div><p>so that <code>res</code> holds:</p> <pre tabindex="0"><code>(20, 40, 60.0) </code></pre><p>How to implement this?</p> <p>This is very similar to our earlier <code>for_each_tuple2</code>, but instead of discarding the results we return them packed into another tuple. Here’s the code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">TupleT</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Fn</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="na">[[nodiscard]]</span> <span class="k">auto</span> <span class="n">transform_tuple</span><span class="p">(</span><span class="n">TupleT</span><span class="o">&amp;&amp;</span> <span class="n">tp</span><span class="p">,</span> <span class="n">Fn</span><span class="o">&amp;&amp;</span> <span class="n">fn</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">apply</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="o">&amp;</span><span class="n">fn</span><span class="p">]</span><span class="o">&lt;</span><span class="k">typename</span> <span class="p">...</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;&amp;</span> <span class="p">...</span><span class="n">args</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">make_tuple</span><span class="p">(</span><span class="n">fn</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">args</span><span class="p">))...);</span> </span></span><span class="line"><span class="cl"> <span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">TupleT</span><span class="o">&gt;</span><span class="p">(</span><span class="n">tp</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Key points:</p> <ul> <li>We use <code>std::apply</code> to expand the tuple into a parameter pack.</li> <li>Inside the lambda, we forward each argument and apply <code>fn</code>.</li> <li>Finally, we pack the results into a new <code>std::tuple</code> via <code>std::make_tuple</code>.</li> </ul> <p>The <code>[[nodiscard]]</code> attribute is optional, but it helps warn you if you call <code>transform_tuple</code> and forget to use the result.</p> <p>Demo</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">tuple</span> <span class="n">tp</span> <span class="p">{</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mf">30.0</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">res</span> <span class="o">=</span> <span class="n">transform_tuple</span><span class="p">(</span><span class="n">tp</span><span class="p">,</span> <span class="p">[](</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">});</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">for_each_tuple2</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="p">[](</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">x</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">});</span> </span></span></code></pre></div><p>Output:</p> <pre tabindex="0"><code>20 40 60 </code></pre><p>See it live <a href="https://godbolt.org/z/1f3Ea7vsK">on Compiler Explorer</a>.</p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>It was a cool story, and I hope you learned a bit about templates.</p> <p>The background task was to print tuples elements and have a way to transform them. During the process, we went through variadic templates, index sequence, template argument deduction rules and tricks, std::apply, and removing references.</p> <p>I&rsquo;m happy to discuss changes and improvements. Let me know in the comments below the article about your ideas.</p> <ul> <li>See the part one here: <a href="https://www.cppstories.com/2022/tuple-iteration-basics/">C++ Templates: How to Iterate through std::tuple: the Basics - C++ Stories</a>.</li> <li>And the third part: <a href="https://www.cppstories.com/2025/tuple-iteration-cpp26/">C++ Templates: How to Iterate through std::tuple: C++26 Packs and Expansion Statements - C++ Stories</a></li> </ul> <h4 id="references"> References: </h4> <ul> <li><a href="https://amzn.to/3GMx8Uu">Effective Modern C++</a> by Scott Meyers</li> <li><a href="http://amzn.to/2wtoENU">C++ Templates: The Complete Guide (2nd Edition)</a> by David Vandevoorde, Nicolai M. Josuttis, Douglas Gregor</li> </ul> Structured bindings in C++17, 8 years later https://www.cppstories.com/2025/structured-bindings-cpp26-updates/ Sun, 31 Aug 2025 00:00:00 +0000 https://www.cppstories.com/2025/structured-bindings-cpp26-updates/ <p>Structured binding is a C++17 feature that allows you to bind multiple variables to the elements of a structured object, such as a tuple or struct. This can make your code more concise and easier to read, especially when working with complex data structures. On this blog, we already covered this functionality, but we&rsquo;ll talk about some good C++26 additions and real code use cases.</p> <h2 id="iterating-through-maps"> Iterating through maps <a class="hash-link" href="#iterating-through-maps" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>An excellent demonstration of structured bindings is an iteration through a map object.</p> <p>If you have a <code>std::map</code> of elements, you might know that internally, they are stored as pairs of <code>&lt;const Key, ValueType&gt;</code>.</p> <p>Now, when you iterate through elements, you can do:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">elem</span> <span class="p">:</span> <span class="n">myMap</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span> </span></span></code></pre></div><p>You need to write <code>elem.first</code> and <code>elem.second</code> to refer to the key and the value.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="n">KeyType</span><span class="p">,</span> <span class="n">ValueType</span><span class="o">&gt;</span> <span class="n">myMap</span> <span class="o">=</span> <span class="n">getMap</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="c1">// C++14: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">elem</span> <span class="p">:</span> <span class="n">myMap</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// elem.first - is the key </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// elem.second - is the value </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span></code></pre></div><p>One of the <strong>coolest use cases</strong> of structured binding is that we can use it inside a range-based for loop:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// C++17: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[</span><span class="n">key</span><span class="p">,</span><span class="n">val</span><span class="p">]</span> <span class="o">:</span> <span class="n">myMap</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// use key/value directly </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span></code></pre></div><p>In the above example, we bind to a pair of <code>[key, val]</code> so we can use those names in the loop. Before C++17, you had to operate on an iterator from the map - which returns a pair <code>&lt;first, second&gt;</code>. Using the real names <code>key/value</code> is more expressive.</p> <p>The above technique can be used in the following example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;map&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">mapCityPopulation</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="s">&#34;Beijing&#34;</span><span class="p">,</span> <span class="mi">21&#39;707&#39;000</span> <span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="s">&#34;London&#34;</span><span class="p">,</span> <span class="mi">8&#39;787&#39;892</span> <span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="s">&#34;New York&#34;</span><span class="p">,</span> <span class="mi">8&#39;622&#39;698</span> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span><span class="p">[</span><span class="n">city</span><span class="p">,</span> <span class="n">population</span><span class="p">]</span> <span class="o">:</span> <span class="n">mapCityPopulation</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">city</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">population</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/59EToMazY">@Compiler Explorer</a></p> <p>In the loop body, you can safely use the <code>city</code> and <code>population</code> variables.</p> <h2 id="the-syntax"> The Syntax <a class="hash-link" href="#the-syntax" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The basic syntax for structured bindings is as follows:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="p">...]</span> <span class="o">=</span> <span class="n">expression</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="p">...]</span> <span class="p">{</span> <span class="n">expression</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="p">...]</span> <span class="p">(</span> <span class="n">expression</span> <span class="p">);</span> </span></span></code></pre></div><p>The compiler introduces all identifiers from the <code>a, b, c, ...</code> list as names in the surrounding scope and binds them to sub-objects or elements of the object denoted by the expression.</p> <p>Behind the scenes, the compiler might generate the following <strong>pseudo code</strong>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">tempTuple</span> <span class="o">=</span> <span class="n">expression</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">a</span> <span class="o">=</span> <span class="n">tempTuple</span><span class="p">.</span><span class="n">first</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">b</span> <span class="o">=</span> <span class="n">tempTuple</span><span class="p">.</span><span class="n">second</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">c</span> <span class="o">=</span> <span class="n">tempTuple</span><span class="p">.</span><span class="n">third</span><span class="p">;</span> </span></span></code></pre></div><p>Conceptually, the expression is copied into a tuple-like object (<code>tempTuple</code>) with member variables that are exposed through <code>a</code>, <code>b</code> and <code>c</code>. However, the variables <code>a</code>, <code>b</code>, and <code>c</code> are not references; they are aliases (or bindings) to the generated object member variables. The temporary object has a unique name assigned by the compiler.</p> <p>For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">pair</span> <span class="n">a</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.0f</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="n">a</span><span class="p">;</span> </span></span></code></pre></div><p><code>x</code> binds to <code>int</code> stored in the generated object that is a copy of <code>a</code>. And similarly, <code>y</code> binds to <code>float</code>.</p> <p>I don&rsquo;t want to repeat myself, so please see this blog post - <a href="https://www.cppstories.com/2022/structured-bindings/">Structured bindings in C++17, 5 years later - C++ Stories</a>, or my <a href="https://leanpub.com/cpp17indetail">book - C++17 in Detail</a> for details about bindings.</p> <h2 id="real-code"> Real code <a class="hash-link" href="#real-code" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Let&rsquo;s have a look at some code in the real projects. I found the following use cases:</p> <h4 id="from-chars-handling"> From chars handling </h4> <p><a href="https://github.com/microsoft/onnxruntime/blob/69ec7b17307f2b94e20199220108e7a415377cf1/onnxruntime/core/providers/migraphx/migraphx_execution_provider_utils.h#L348">onnxruntime/migraphx_execution_provider_utils.h</a></p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kr">inline</span> <span class="kt">int</span> <span class="nf">ToInteger</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">sv</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="k">auto</span> <span class="p">[</span><span class="n">_</span><span class="p">,</span> <span class="n">ec</span><span class="p">]</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">from_chars</span><span class="p">(</span><span class="n">sv</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="n">sv</span><span class="p">.</span><span class="n">data</span><span class="p">()</span> <span class="o">+</span> <span class="n">sv</span><span class="p">.</span><span class="n">length</span><span class="p">(),</span> <span class="n">result</span><span class="p">);</span> <span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="p">())</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">result</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="n">ORT_THROW</span><span class="p">(</span><span class="s">&#34;invalid input for conversion to integer&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Here, <code>std::from_chars</code> returns a <code>std::from_chars_result</code> with two fields: <code>ptr</code> and <code>ec</code>. The code only cares about the error code, so structured bindings make it easy to ignore the pointer (<code>_</code>) and directly test <code>ec</code>.</p> <p>Read more about <code>from_chars</code> here: <a href="https://www.cppstories.com/2018/12/fromchars/">C++ String Conversion: Exploring std::from_chars in C++17 to C++26 - C++ Stories</a></p> <h4 id="unmap"> Unmap </h4> <p><a href="https://github.com/microsoft/onnxruntime/blob/69ec7b17307f2b94e20199220108e7a415377cf1/onnxruntime/core/platform/posix/env.cc#L68">onnxruntime/env.cc</a></p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">void</span> <span class="nf">UnmapFile</span><span class="p">(</span><span class="kt">void</span><span class="o">*</span> <span class="n">addr</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">len</span><span class="p">)</span> <span class="k">noexcept</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">munmap</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">len</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="p">[</span><span class="n">err_no</span><span class="p">,</span> <span class="n">err_msg</span><span class="p">]</span> <span class="o">=</span> <span class="n">GetErrnoInfo</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">LOGS_DEFAULT</span><span class="p">(</span><span class="n">ERROR</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;munmap failed. error code: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">err_no</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; error msg: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">err_msg</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p><code>GetErrnoInfo()</code> returns both an error number and a message. Using structured bindings makes the call-site clean and self-documenting, with no extra boilerplate for <code>std::pair</code> access (<code>.first</code>, <code>.second</code>).</p> <h4 id="softmax"> Softmax </h4> <p><a href="https://github.com/microsoft/onnxruntime/blob/69ec7b17307f2b94e20199220108e7a415377cf1/onnxruntime/core/providers/xnnpack/math/softmax.cc#L33">onnxruntime/softmax</a></p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"> <span class="k">auto</span> <span class="p">[</span><span class="n">scale_tensor</span><span class="p">,</span> <span class="n">zero_tensor</span><span class="p">]</span> <span class="o">=</span> <span class="n">GetQuantizationZeroPointAndScale</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">node_unit</span><span class="p">.</span><span class="n">Outputs</span><span class="p">()[</span><span class="mi">0</span><span class="p">]);</span> </span></span><span class="line"><span class="cl"> <span class="n">Initializer</span> <span class="nf">q_scale</span><span class="p">(</span><span class="n">graph</span><span class="p">.</span><span class="n">GetGraph</span><span class="p">(),</span> <span class="o">*</span><span class="n">scale_tensor</span><span class="p">,</span> <span class="n">node_unit</span><span class="p">.</span><span class="n">ModelPath</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">fabs</span><span class="p">(</span><span class="n">q_scale</span><span class="p">.</span><span class="n">DataAsSpan</span><span class="o">&lt;</span><span class="kt">float</span><span class="o">&gt;</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mf">1.0f</span> <span class="o">/</span> <span class="mf">256.0f</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mf">0.0001f</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">break</span><span class="p">;</span> </span></span></code></pre></div><p>Here, a helper function returns both the quantization scale and zero-point tensors. Structured bindings allow unpacking them directly into named variables, instead of handling them as <code>std::pair</code> elements or temporary structs.</p> <h4 id="iteration"> Iteration </h4> <p><a href="https://github.com/microsoft/onnxruntime/blob/69ec7b17307f2b94e20199220108e7a415377cf1/onnxruntime/core/framework/prepacked_weights_container.h#L146">onnxruntime/prepacked_weights_container.h</a></p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="nf">GetNumberOfKeyedBlobsForWriting</span><span class="p">()</span> <span class="k">const</span> <span class="k">noexcept</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[</span><span class="n">_</span><span class="p">,</span> <span class="n">keys</span><span class="p">]</span> <span class="o">:</span> <span class="n">weight_prepacks_for_saving_</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">result</span> <span class="o">+=</span> <span class="n">keys</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">result</span><span class="p">;</span> </span></span></code></pre></div><p>The standard use case for structured bindings and iteration over a map.</p> <h4 id="hash-computation"> Hash computation </h4> <p><a href="https://github.com/openvinotoolkit/openvino/blob/b85c4bc559ca38c3c7b63773769f20f7c9c87dc8/src/inference/src/dev/compilation_context.cpp#L67">openvinotoolkit/compilation_context.cpp</a></p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[</span><span class="n">name</span><span class="p">,</span> <span class="n">option</span><span class="p">]</span> <span class="o">:</span> <span class="n">compileOptions</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">seed</span> <span class="o">=</span> <span class="n">hash_combine</span><span class="p">(</span><span class="n">seed</span><span class="p">,</span> <span class="n">name</span> <span class="o">+</span> <span class="n">option</span><span class="p">.</span><span class="n">as</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span></code></pre></div><p>Another use case for iteration over a container.</p> <h2 id="c17c20-changes"> C++17/C++20 changes <a class="hash-link" href="#c17c20-changes" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>During the work on C++20, there were several proposals that improved the initial support for structured bindings, most of them are added as defect reports (DR) against C++17:</p> <h4 id="relaxing-the-structured-bindings-customization-point-finding-rules---p0961httpswg21linkp0961"> Relaxing the structured bindings customization point finding rules - <a href="https://wg21.link/P0961">P0961</a> </h4> <p>The proposal relaxes the rule so that only member <strong>template</strong> <code>get&lt;I&gt;</code> functions are considered, while plain <code>get()</code> members no longer interfere, making structured bindings more flexible and consistent.</p> <h4 id="allow-structured-bindings-to-accessible-members---p0969httpswg21linkp0969"> Allow structured bindings to accessible members - <a href="https://wg21.link/P0969">P0969</a> </h4> <p>P0969 fixed an odd inconsistency in C++17: structured bindings could only bind to <strong>public</strong> data members (or members of public bases), even if the member was actually accessible in the current scope. This meant that code which could access a private member via friendship, inheritance, or even within the class itself, failed when using structured bindings. C++20 relaxed this rule so that structured bindings follow the <strong>normal accessibility rules of C++</strong>: if you can name the member in that scope, you can also bind to it. This made structured bindings consistent with all other forms of member access.</p> <h4 id="extending-structured-bindings-to-be-more-like-variable-declarations---p1091httpswg21linkp1091"> Extending structured bindings to be more like variable declarations - <a href="https://wg21.link/P1091">P1091</a> </h4> <p><strong>P1091R3</strong> made structured bindings feel more like “real” variable declarations in C++20. In C++17 they were restricted and somewhat “magical”: you couldn’t mark them <code>static</code>, <code>thread_local</code>, or capture them in lambdas. This proposal removed those inconsistencies — now structured bindings can carry storage-class specifiers, be captured by value in lambdas, and behave consistently with ordinary variables. It brought them closer to being true first-class citizens in the language.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;tuple&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="k">auto</span> <span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="p">{</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">lambda</span> <span class="o">=</span> <span class="p">[</span><span class="o">=</span><span class="p">]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;x = &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">x</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, y = &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">y</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">lambda</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/MYqhb5ne6">@Compiler Explorer</a></p> <h4 id="reference-capture-of-structured-bindings---p1381httpswg21linkp1381"> Reference capture of structured bindings - <a href="https://wg21.link/P1381">P1381</a> </h4> <p>The previous proposal allowed lambdas to capture structyred bindings by value, and now the missing part is to capture by reference:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Foo</span> <span class="p">{</span> <span class="kt">int</span> <span class="n">x</span><span class="p">;</span> <span class="kt">int</span> <span class="n">y</span><span class="p">;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Foo</span> <span class="n">foo</span><span class="p">{</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">]</span> <span class="o">=</span> <span class="n">foo</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">by_val</span> <span class="o">=</span> <span class="p">[</span><span class="o">=</span><span class="p">]</span> <span class="p">{</span> <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">by_ref</span> <span class="o">=</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">]</span> <span class="p">{</span> <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">by_ref</span><span class="p">();</span> <span class="c1">// 30 </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/qsnEqsqTa">@Compiler Explorer</a></p> <h2 id="c26-updates"> C++26 Updates <a class="hash-link" href="#c26-updates" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In C++26, we have at least four new features that went into the Standard:</p> <h4 id="attributes-for-structured-bindings---p0609r3httpswg21linkp0609r3"> Attributes for structured bindings - <a href="https://wg21.link/P0609R3">P0609R3</a> </h4> <p>There are not many sensible attributes that can be applied to variables, but we can now try <code>maybe_unused</code> attribute on a part of structured binding:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">pair</span> <span class="n">xy</span> <span class="p">{</span> <span class="mf">42.3</span><span class="p">,</span> <span class="mf">100.1</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="na">[[maybe_unused]]]</span> <span class="o">=</span> <span class="n">xy</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{}&#34;</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span> </span></span></code></pre></div><p>see <a href="https://godbolt.org/z/seKTqd71x">@Compiler Explorer</a></p> <p>The interesting thing is that the attribute is applied <strong>after</strong> the name of the binding.</p> <h4 id="structured-binding-declaration-as-a-condition----p0963r3httpswg21linkp0963r3"> Structured binding declaration as a condition - <a href="https://wg21.link/P0963R3">P0963R3</a> </h4> <p>This paper proposes to allow structured binding declarations with initializers appearing in place of the conditions in <code>if</code>, <code>while</code>, <code>for</code>, and <code>switch</code> statements.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Point</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">x</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">y</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">explicit</span> <span class="k">operator</span> <span class="nf">bool</span><span class="p">()</span> <span class="k">const</span> <span class="k">noexcept</span> <span class="p">{</span> <span class="k">return</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">Point</span> <span class="nf">createPoint</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">Point</span> <span class="p">{</span> <span class="mi">10</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="mi">10</span><span class="o">*</span><span class="n">a</span> <span class="p">};</span> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="k">auto</span> <span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="n">createPoint</span><span class="p">(</span><span class="mi">100</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;point is true&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/o6b3zfqjv">@Compiler Explorer</a></p> <p>The crucial part here is that the conversion to <code>bool</code> happens on the object that we bind to.</p> <p>Note that the following code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">pair</span> <span class="n">xy</span> <span class="p">{</span> <span class="mf">42.3</span><span class="p">,</span> <span class="mf">100.1</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="k">auto</span> <span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="n">xy</span><span class="p">;</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="mf">40.0</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;x is larger than 40&#34;</span><span class="p">);</span> </span></span></code></pre></div><p>Worked before C++26.</p> <p>Thanks to <a href="https://github.com/hanickadot">hanickadot</a> for the <a href="https://github.com/fenbf/cppstories-discussions/issues/158#issuecomment-3242839406">comment</a> and explanations!</p> <h4 id="structured-bindings-can-introduce-a-pack----p1061r10httpswg21linkp1061r10"> Structured bindings can introduce a pack - <a href="https://wg21.link/P1061R10">P1061R10</a> </h4> <p>This is a really powerful feature!</p> <p>Before C++26, structured bindings required you to write all identifiers explicitly<code> (auto [x, y, z] = ...;)</code>. Converting a tuple to a pack is awkward—you need <code>std::apply</code> or <code>index_sequence</code>. But now structured bindings can introduce a pack using <code>...identifier</code>. This gives you a parameter-pack-like expansion directly from a tuple/array/aggregate inside a structured binding.</p> <p>In short:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="p">[</span><span class="n">head</span><span class="p">,</span> <span class="p">...</span><span class="n">rest</span><span class="p">]</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="c1">// head = 1, rest... expands to (2,3,4) </span></span></span></code></pre></div><p>Here&rsquo;s a super cool (and mind-boggling) example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Generic dot product for any tuple-like / array / aggregate supported by structured bindings. </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span> <span class="nc">P</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Q</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="k">auto</span> <span class="n">dot_product</span><span class="p">(</span><span class="k">const</span> <span class="n">P</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">,</span> <span class="k">const</span> <span class="n">Q</span><span class="o">&amp;</span> <span class="n">q</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Bind all elements of each input into packs. </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[...</span><span class="n">ps</span><span class="p">]</span> <span class="o">=</span> <span class="n">p</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[...</span><span class="n">qs</span><span class="p">]</span> <span class="o">=</span> <span class="n">q</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// (Optional) sanity check: both must have the same size </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">static_assert</span><span class="p">(</span><span class="k">sizeof</span><span class="p">...(</span><span class="n">ps</span><span class="p">)</span> <span class="o">==</span> <span class="k">sizeof</span><span class="p">...(</span><span class="n">qs</span><span class="p">),</span> <span class="s">&#34;Mismatched sizes&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Elementwise multiply, then fold with + </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">return</span> <span class="p">((</span><span class="n">ps</span> <span class="o">*</span> <span class="n">qs</span><span class="p">)</span> <span class="o">+</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">3</span><span class="o">&gt;</span> <span class="n">a</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">3</span><span class="o">&gt;</span> <span class="n">b</span><span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">static_assert</span><span class="p">(</span><span class="n">dot_product</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="o">==</span> <span class="mi">32</span><span class="p">);</span> </span></span></code></pre></div><p>Here&rsquo;s the link to <a href="https://godbolt.org/z/5hWTE8YdY">Compiler Explorer</a></p> <h4 id="constexpr-structured-bindings-and-references-to-constexpr-variables----p2686r5httpswg21linkp2686r5"> constexpr structured bindings and references to constexpr variables - <a href="https://wg21.link/P2686R5">P2686R5</a> </h4> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">constexpr</span> <span class="k">auto</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">]</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">a</span> <span class="o">*</span> <span class="n">b</span> <span class="o">==</span> <span class="mi">6</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Unfortunately, as of Sept 2025, no compiler supports this.</p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In this text, we explored structured bindings and how they evolved over the recent C++ Standards. This feature was a big &ldquo;magic&rdquo; and used some compiler tricks to work, which also created some restrictions. Now (especially in C++26), those bindings can be used almost like standard variables.</p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Do you use structured bindings?</li> <li>What are the most common use cases for you?</li> </ul> <p>Share your feedback in the comments below.</p> How to Avoid Thread-Safety Cost for Functions' static Variables https://www.cppstories.com/2025/thread_safety_function_statics/ Sat, 23 Aug 2025 00:00:00 +0000 https://www.cppstories.com/2025/thread_safety_function_statics/ <p>In this blog post, we&rsquo;ll look at static variables defined in a function scope. We&rsquo;ll see how they are implemented and how to use them. What&rsquo;s more, we&rsquo;ll discuss several cases where we can avoid extra thread-safety cost.</p> <p>Let&rsquo;s start.</p> <h2 id="introduction"> Introduction <a class="hash-link" href="#introduction" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>As you may know, C++ offers a way to define static variables in a function/block scope:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">foo</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="kt">int</span> <span class="n">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="o">++</span><span class="n">counter</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Above, the <code>counter</code> variable will be initialized and created when <code>foo()</code> is invoked for the first time. In other words, a static local variable is initialized lazily. The <code>counter</code> is kept &ldquo;outside&rdquo; the function&rsquo;s stack space. This allows, for example, to keep the state, but limit the visibility of the global object.</p> <p>Here&rsquo;s the full example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">foo</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="kt">int</span> <span class="n">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="o">++</span><span class="n">counter</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">foo</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">foo</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">foo</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">finalCounter</span> <span class="o">=</span> <span class="n">foo</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">finalCounter</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/sP91Eofqx">@Compiler Explorer</a></p> <p>If you run the program, you&rsquo;ll get <code>4</code> as the output.</p> <p>Static local variables, since C++11, are guaranteed to be initialized in a <strong>thread-safe way</strong>. The object will be initialized only once if multiple threads enter a function with such a variable. Have a look below:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;thread&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Value</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Value</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="o">:</span> <span class="n">v</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Value(&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">v</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="o">~</span><span class="n">Value</span><span class="p">()</span> <span class="k">noexcept</span> <span class="p">{</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;~Value(&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">v</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">v</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">foo</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="n">Value</span> <span class="n">x</span> <span class="p">{</span> <span class="mi">10</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">jthread</span> <span class="n">worker1</span> <span class="p">{</span> <span class="n">foo</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">jthread</span> <span class="n">worker2</span> <span class="p">{</span> <span class="n">foo</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">jthread</span> <span class="n">worker3</span> <span class="p">{</span> <span class="n">foo</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/8qzvMsMf8">@Compiler Explorer</a></p> <p>The example creates three threads that call the <code>foo()</code> simple function.</p> <p>However, on GCC, you can also try compiling with the following flags:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">-std=c++20 -lpthread -fno-threadsafe-statics </span></span></code></pre></div><p>And then the output might be as follows:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Value(Value(1010) </span></span><span class="line"><span class="cl">) </span></span><span class="line"><span class="cl">Value(10) </span></span><span class="line"><span class="cl">~Value(10) </span></span><span class="line"><span class="cl">~Value(10) </span></span><span class="line"><span class="cl">~Value(10) </span></span></code></pre></div><p>Three static objects are created now!</p> <p>On Windows, MSVC, you can play with <code>/Zc:threadSafeInit</code> and disable this behaviour. See <a href="https://learn.microsoft.com/en-us/cpp/build/reference/zc-threadsafeinit-thread-safe-local-static-initialization?view=msvc-170">/Zc:threadSafeInit (Thread-safe Local Static Initialization) | Microsoft Learn</a></p> <p>Thread safety may be beneficial in most cases, for example, when you want to implement a singleton (Meyers Singleton, it defines the entity as a static variable in a function&hellip;).</p> <h2 id="how-much-does-this-cost"> How much does this cost? <a class="hash-link" href="#how-much-does-this-cost" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>To understand the cost of the static local variables, let&rsquo;s consider this popular SQ question:</p> <p><a href="https://stackoverflow.com/questions/21488559/is-there-a-penalty-for-using-static-variables-in-c11">c++ - Is there a penalty for using static variables in C++11 - Stack Overflow</a></p> <p>In short: not much :)</p> <p>The answer contains the following benchmark setup:</p> <ul> <li>Two versions tested: <ol> <li><strong>Local static</strong> inside a function</li> <li><strong>Global static</strong> at namespace scope</li> </ol> </li> <li>Both return a <code>const std::vector&lt;int&gt;&amp;</code> with <code>{1, 2, 3}</code>.</li> <li>Measured over <strong>500 million iterations</strong>, summing vector elements.</li> <li>Timed using <code>std::chrono</code> with barriers to avoid reordering.</li> </ul> <p><strong>Results (first benchmark, indirect function calls):</strong> (warning the code is from 2014!)</p> <ul> <li><strong>Clang</strong>: local = 4618 ms, global = 4392 ms → local slower by ~0.45 ns per call.</li> <li><strong>GCC</strong>: local = 4181 ms, global = 4418 ms → local faster by ~0.47 ns per call.</li> <li>Conclusion: variance is tiny, compiler-dependent.</li> </ul> <p><strong>Second benchmark (function objects for better inlining):</strong></p> <ul> <li><strong>GCC</strong>: local = 3803 ms, global = 2323 ms → global faster by ~2.96 ns per call.</li> <li><strong>Clang</strong>: local = 4183 ms, global = 3253 ms → global faster by ~1.86 ns per call.</li> <li>This matches the intuition that a global avoids the guard check entirely, while a local static still needs a fast-path check.</li> </ul> <p>Takeaway:</p> <ul> <li>Function-local statics in C++11+ are initialized exactly once, thread-safely.</li> <li>After initialization, calls incur only a very small, predictable guard check (~1–3 ns in tight loops).</li> <li>In most real-world code, the difference is negligible; choose the style that best fits your design.</li> <li>If absolute lowest per-call overhead is needed in a very hot path, a namespace-scope <code>constexpr</code>/<code>constinit</code> global removes even that guard.</li> </ul> <h2 id="how-to-avoid-the-cost"> How to avoid the cost <a class="hash-link" href="#how-to-avoid-the-cost" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>We&rsquo;re equipped with the basic knowledge, and now let&rsquo;s consider how to limit the cost of thread-safety. Consider the following super-simple example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;algorithm&gt; // std::find</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">is_blocked_id</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">blocked_ids</span><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="mi">101</span><span class="p">,</span> <span class="mi">202</span><span class="p">,</span> <span class="mi">303</span><span class="p">,</span> <span class="mi">404</span><span class="p">,</span> <span class="mi">505</span> <span class="c1">// possibly a longer list... </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">find</span><span class="p">(</span><span class="n">blocked_ids</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">blocked_ids</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">id</span><span class="p">)</span> <span class="o">!=</span> <span class="n">blocked_ids</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="nl">id</span> <span class="p">:</span> <span class="p">{</span><span class="mi">101</span><span class="p">,</span> <span class="mi">150</span><span class="p">,</span> <span class="mi">202</span><span class="p">,</span> <span class="mi">999</span><span class="p">})</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{} is blocked: {}&#34;</span><span class="p">,</span> <span class="n">id</span><span class="p">,</span> <span class="n">is_blocked_id</span><span class="p">(</span><span class="n">id</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/GrarMETMh">@Compiler Explorer</a></p> <p>The main function iterates through some ids and checks them through <code>is_blocked_id</code> function. The function then uses a static const vector to store &ldquo;suspicious&rdquo; numbers.</p> <p>And here&rsquo;s the generated code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-asm" data-lang="asm"><span class="line"><span class="cl"><span class="err">&#34;</span><span class="nf">is_blocked_id</span><span class="p">(</span><span class="no">int</span><span class="p">)</span><span class="err">&#34;</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="nf">push</span> <span class="no">rbp</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">rbp</span><span class="p">,</span> <span class="no">rsp</span> </span></span><span class="line"><span class="cl"> <span class="nf">push</span> <span class="no">r14</span> </span></span><span class="line"><span class="cl"> <span class="nf">push</span> <span class="no">r13</span> </span></span><span class="line"><span class="cl"> <span class="nf">push</span> <span class="no">r12</span> </span></span><span class="line"><span class="cl"> <span class="nf">push</span> <span class="no">rbx</span> </span></span><span class="line"><span class="cl"> <span class="nf">sub</span> <span class="no">rsp</span><span class="p">,</span> <span class="mi">64</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">DWORD</span> <span class="no">PTR</span> <span class="p">[</span><span class="no">rbp-84</span><span class="p">],</span> <span class="no">edi</span> </span></span><span class="line"><span class="cl"> <span class="nf">movzx</span> <span class="no">eax</span><span class="p">,</span> <span class="no">BYTE</span> <span class="no">PTR</span> <span class="err">&#34;</span><span class="no">guard</span> <span class="no">variable</span> <span class="no">for</span> <span class="no">is_blocked_id</span><span class="p">(</span><span class="no">int</span><span class="p">)::</span><span class="no">blocked_ids</span><span class="err">&#34;</span><span class="p">[</span><span class="no">rip</span><span class="p">]</span> </span></span><span class="line"><span class="cl"> <span class="nf">test</span> <span class="no">al</span><span class="p">,</span> <span class="no">al</span> </span></span><span class="line"><span class="cl"> <span class="nf">sete</span> <span class="no">al</span> </span></span><span class="line"><span class="cl"> <span class="nf">test</span> <span class="no">al</span><span class="p">,</span> <span class="no">al</span> </span></span><span class="line"><span class="cl"> <span class="nf">je</span> <span class="no">.L216</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">edi</span><span class="p">,</span> <span class="no">OFFSET</span> <span class="no">FLAT</span><span class="p">:</span><span class="err">&#34;</span><span class="no">guard</span> <span class="no">variable</span> <span class="no">for</span> <span class="no">is_blocked_id</span><span class="p">(</span><span class="no">int</span><span class="p">)::</span><span class="no">blocked_ids</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">call</span> <span class="err">&#34;</span><span class="no">__cxa_guard_acquire</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="na">...</span> </span></span></code></pre></div><p>As you can see, we have some extra calls to <code>__cxa_guard_acquire</code> and thus each time you call the function, we have some overhead.</p> <h3 id="some-issues"> Some issues <a class="hash-link" href="#some-issues" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>There are a few cases to consider.</p> <ul> <li>While in Mayer&rsquo;s singleton thread safety was essential, here we have a constant object, so maybe we can do something with this knowledge?</li> <li>Since we use <code>std::vector</code> there&rsquo;s extra memory allocation going on. Do we need it?</li> </ul> <p>What to improve: In short, we need to move our dynamic initialization to constant initialization. Since our data is const, there&rsquo;s no need to pay an extra price at runtime. The compiler can initialize all data at compile time and write it to the binary.</p> <p>How to achieve this?</p> <p>One way is to push the vector outside the function scope, that way we&rsquo;ll lose the &ldquo;locality&rdquo; but the compiler will ensure it&rsquo;s properly initialized before even the main function starts:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;algorithm&gt; // std::find</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">blocked_ids</span><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="mi">101</span><span class="p">,</span> <span class="mi">202</span><span class="p">,</span> <span class="mi">303</span><span class="p">,</span> <span class="mi">404</span><span class="p">,</span> <span class="mi">505</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">is_blocked_id</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">find</span><span class="p">(</span><span class="n">blocked_ids</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">blocked_ids</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">id</span><span class="p">)</span> <span class="o">!=</span> <span class="n">blocked_ids</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="nl">id</span> <span class="p">:</span> <span class="p">{</span><span class="mi">101</span><span class="p">,</span> <span class="mi">150</span><span class="p">,</span> <span class="mi">202</span><span class="p">,</span> <span class="mi">999</span><span class="p">})</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{} is blocked: {}&#34;</span><span class="p">,</span> <span class="n">id</span><span class="p">,</span> <span class="n">is_blocked_id</span><span class="p">(</span><span class="n">id</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/5TKWT6o76">@Compiler Explorer</a></p> <p>Now the generated code is a bit better:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-asm" data-lang="asm"><span class="line"><span class="cl"><span class="err">&#34;</span><span class="nf">is_blocked_id</span><span class="p">(</span><span class="no">int</span><span class="p">)</span><span class="err">&#34;</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="nf">push</span> <span class="no">rbp</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">rbp</span><span class="p">,</span> <span class="no">rsp</span> </span></span><span class="line"><span class="cl"> <span class="nf">push</span> <span class="no">rbx</span> </span></span><span class="line"><span class="cl"> <span class="nf">sub</span> <span class="no">rsp</span><span class="p">,</span> <span class="mi">56</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">DWORD</span> <span class="no">PTR</span> <span class="p">[</span><span class="no">rbp-52</span><span class="p">],</span> <span class="no">edi</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">edi</span><span class="p">,</span> <span class="no">OFFSET</span> <span class="no">FLAT</span><span class="p">:</span><span class="err">&#34;</span><span class="no">blocked_ids</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">call</span> <span class="err">&#34;</span><span class="no">std</span><span class="p">::</span><span class="no">vector</span><span class="err">&lt;</span><span class="no">int</span><span class="p">,</span> <span class="no">std</span><span class="p">::</span><span class="no">allocator</span><span class="err">&lt;</span><span class="no">int</span><span class="err">&gt;</span> <span class="err">&gt;</span><span class="p">::</span><span class="no">end</span><span class="p">()</span> <span class="no">const</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">QWORD</span> <span class="no">PTR</span> <span class="p">[</span><span class="no">rbp-48</span><span class="p">],</span> <span class="no">rax</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">edi</span><span class="p">,</span> <span class="no">OFFSET</span> <span class="no">FLAT</span><span class="p">:</span><span class="err">&#34;</span><span class="no">blocked_ids</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">call</span> <span class="err">&#34;</span><span class="no">std</span><span class="p">::</span><span class="no">vector</span><span class="err">&lt;</span><span class="no">int</span><span class="p">,</span> <span class="no">std</span><span class="p">::</span><span class="no">allocator</span><span class="err">&lt;</span><span class="no">int</span><span class="err">&gt;</span> <span class="err">&gt;</span><span class="p">::</span><span class="no">end</span><span class="p">()</span> <span class="no">const</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">rbx</span><span class="p">,</span> <span class="no">rax</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">edi</span><span class="p">,</span> <span class="no">OFFSET</span> <span class="no">FLAT</span><span class="p">:</span><span class="err">&#34;</span><span class="no">blocked_ids</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">call</span> <span class="err">&#34;</span><span class="no">std</span><span class="p">::</span><span class="no">vector</span><span class="err">&lt;</span><span class="no">int</span><span class="p">,</span> <span class="no">std</span><span class="p">::</span><span class="no">allocator</span><span class="err">&lt;</span><span class="no">int</span><span class="err">&gt;</span> <span class="err">&gt;</span><span class="p">::</span><span class="no">begin</span><span class="p">()</span> <span class="no">const</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">rcx</span><span class="p">,</span> <span class="no">rax</span> </span></span><span class="line"><span class="cl"> <span class="nf">lea</span> <span class="no">rax</span><span class="p">,</span> <span class="p">[</span><span class="no">rbp-52</span><span class="p">]</span> </span></span><span class="line"><span class="cl"> <span class="na">...</span> </span></span></code></pre></div><p>As you can see, there are no guards needed, just the vector handling. The runtime memory allocation is still there, but occurs before the main function enters.</p> <p>But we can do better!</p> <h3 id="better-than-a-vector"> Better than a vector <a class="hash-link" href="#better-than-a-vector" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>As we discussed, there&rsquo;s no need for dynamic allocation here. So, how about using just the <code>std::array</code>?</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">array</span> <span class="n">blocked_ids</span><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="mi">101</span><span class="p">,</span> <span class="mi">202</span><span class="p">,</span> <span class="mi">303</span><span class="p">,</span> <span class="mi">404</span><span class="p">,</span> <span class="mi">505</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">is_blocked_id</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">find</span><span class="p">(</span><span class="n">blocked_ids</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">blocked_ids</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">id</span><span class="p">)</span> <span class="o">!=</span> <span class="n">blocked_ids</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/Y6nPe8zKW">@Compiler Explorer</a></p> <p>The generated code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-asm" data-lang="asm"><span class="line"><span class="cl"><span class="err">&#34;</span><span class="nf">is_blocked_id</span><span class="p">(</span><span class="no">int</span><span class="p">)</span><span class="err">&#34;</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="nf">push</span> <span class="no">rbp</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">rbp</span><span class="p">,</span> <span class="no">rsp</span> </span></span><span class="line"><span class="cl"> <span class="nf">push</span> <span class="no">rbx</span> </span></span><span class="line"><span class="cl"> <span class="nf">sub</span> <span class="no">rsp</span><span class="p">,</span> <span class="mi">24</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">DWORD</span> <span class="no">PTR</span> <span class="p">[</span><span class="no">rbp-20</span><span class="p">],</span> <span class="no">edi</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">edi</span><span class="p">,</span> <span class="no">OFFSET</span> <span class="no">FLAT</span><span class="p">:</span><span class="err">&#34;</span><span class="no">blocked_ids</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">call</span> <span class="err">&#34;</span><span class="no">std</span><span class="p">::</span><span class="no">array</span><span class="err">&lt;</span><span class="no">int</span><span class="p">,</span> <span class="mi">5</span><span class="no">ul</span><span class="err">&gt;</span><span class="p">::</span><span class="no">end</span><span class="p">()</span> <span class="no">const</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">rbx</span><span class="p">,</span> <span class="no">rax</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">edi</span><span class="p">,</span> <span class="no">OFFSET</span> <span class="no">FLAT</span><span class="p">:</span><span class="err">&#34;</span><span class="no">blocked_ids</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">call</span> <span class="err">&#34;</span><span class="no">std</span><span class="p">::</span><span class="no">array</span><span class="err">&lt;</span><span class="no">int</span><span class="p">,</span> <span class="mi">5</span><span class="no">ul</span><span class="err">&gt;</span><span class="p">::</span><span class="no">begin</span><span class="p">()</span> <span class="no">const</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">rcx</span><span class="p">,</span> <span class="no">rax</span> </span></span><span class="line"><span class="cl"> <span class="nf">lea</span> <span class="no">rax</span><span class="p">,</span> <span class="p">[</span><span class="no">rbp-20</span><span class="p">]</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">rdx</span><span class="p">,</span> <span class="no">rax</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">rsi</span><span class="p">,</span> <span class="no">rbx</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">rdi</span><span class="p">,</span> <span class="no">rcx</span> </span></span><span class="line"><span class="cl"> <span class="nf">call</span> <span class="err">&#34;</span><span class="no">int</span> <span class="no">const</span><span class="p">*</span> <span class="no">std</span><span class="p">::</span><span class="no">find</span><span class="err">&lt;</span><span class="no">int</span> <span class="no">const</span><span class="p">*,</span> <span class="no">int</span><span class="err">&gt;</span><span class="p">(</span><span class="no">int</span> <span class="no">const</span><span class="p">*,</span> <span class="no">int</span> <span class="no">const</span><span class="p">*,</span> <span class="no">int</span> <span class="no">const</span><span class="err">&amp;</span><span class="p">)</span><span class="err">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nf">mov</span> <span class="no">rbx</span><span class="p">,</span> <span class="no">rax</span> </span></span></code></pre></div><h3 id="even-better-approach"> Even better approach <a class="hash-link" href="#even-better-approach" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>If you still want to keep numbers in a function scope, there&rsquo;s still a chance to do it, just ensure the collection is initialized at compile time:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">is_blocked_id</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">array</span> <span class="n">blocked_ids</span><span class="p">{</span> <span class="c1">// or constexpr, or constinit! </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="mi">101</span><span class="p">,</span> <span class="mi">202</span><span class="p">,</span> <span class="mi">303</span><span class="p">,</span> <span class="mi">404</span><span class="p">,</span> <span class="mi">505</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">find</span><span class="p">(</span><span class="n">blocked_ids</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">blocked_ids</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">id</span><span class="p">)</span> <span class="o">!=</span> <span class="n">blocked_ids</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>The <code>static const</code> should be good enough for a compiler to use compile-time initialization, assuming the container is implemented in a constexpr way. But to be sure, use <code>constinit</code> or <code>constexpr</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">is_blocked_id</span><span class="p">(</span><span class="kt">int</span> <span class="n">id</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="n">constinit</span> <span class="n">std</span><span class="o">::</span><span class="n">array</span> <span class="n">blocked_ids</span><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="mi">101</span><span class="p">,</span> <span class="mi">202</span><span class="p">,</span> <span class="mi">303</span><span class="p">,</span> <span class="mi">404</span><span class="p">,</span> <span class="mi">505</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">find</span><span class="p">(</span><span class="n">blocked_ids</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">blocked_ids</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">id</span><span class="p">)</span> <span class="o">!=</span> <span class="n">blocked_ids</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Here&rsquo;s the article about those keywords if you want to know more: <a href="https://www.cppstories.com/2022/const-options-cpp20/">const vs constexpr vs consteval vs constinit in C++20 - C++ Stories</a>.</p> <h3 id="more-complex-types"> More complex types <a class="hash-link" href="#more-complex-types" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>In a real-life application, you will work not only with arrays of simple integers. Maps of strings, maps of custom data types, and much more. In that case, moving things to compile-time might not be straightforward. Yet, there are steps you can try.</p> <p>Here are some examples, just to get started:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Point</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">x</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">y</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="kt">bool</span> <span class="k">operator</span><span class="o">==</span><span class="p">(</span><span class="k">const</span> <span class="n">Point</span><span class="o">&amp;</span> <span class="n">pt</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">pt</span><span class="p">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">x</span> <span class="o">&amp;&amp;</span> <span class="n">pt</span><span class="p">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">y</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">is_blocked_point</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="n">constinit</span> <span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="n">Point</span><span class="p">,</span><span class="mi">6</span><span class="o">&gt;</span> <span class="n">blocked_pts</span><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Point</span><span class="p">{</span><span class="mi">101</span><span class="p">,</span> <span class="mi">101</span><span class="p">},</span> <span class="n">Point</span><span class="p">{</span><span class="mi">202</span><span class="p">,</span> <span class="mi">202</span><span class="p">},</span> <span class="n">Point</span><span class="p">{</span><span class="mi">303</span><span class="p">,</span> <span class="mi">303</span><span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="n">Point</span><span class="p">{</span><span class="mi">404</span><span class="p">,</span> <span class="mi">404</span><span class="p">},</span> <span class="n">Point</span><span class="p">{</span><span class="mi">505</span><span class="p">,</span> <span class="mi">505</span><span class="p">},</span> <span class="n">Point</span><span class="p">{</span><span class="mi">606</span><span class="p">,</span> <span class="mi">606</span><span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">find</span><span class="p">(</span><span class="n">blocked_pts</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">blocked_pts</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="p">{</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">})</span> <span class="o">!=</span> <span class="n">blocked_pts</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/4sY6xW1x7">@Compiler Explorer</a></p> <p>The point class is <code>constexpr</code> implicitly, and the compiler can use it at compile-time.</p> <p>Or wth strings:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">is_blocked_name</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">name</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="n">constinit</span> <span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span><span class="p">,</span> <span class="mi">6</span><span class="o">&gt;</span> <span class="n">blocked_names</span><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="s">&#34;alice&#34;</span><span class="p">,</span> <span class="s">&#34;bob&#34;</span><span class="p">,</span> <span class="s">&#34;charlie&#34;</span><span class="p">,</span> <span class="s">&#34;dora&#34;</span><span class="p">,</span> <span class="s">&#34;eve&#34;</span><span class="p">,</span> <span class="s">&#34;mallory&#34;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">find</span><span class="p">(</span><span class="n">blocked_names</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">blocked_names</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">name</span><span class="p">)</span> <span class="o">!=</span> <span class="n">blocked_names</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/G5GKjTr1P">@Compiler Explorer</a></p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In the article, we went from a simple example that illustrates how a static variable inside a function works, to advanced scenarios where we want to limit the cost of thread-safety.</p> <p>Always measure, measure, measure. In most cases, the performance hit added for a local static variable will be super small, but in your hot path, it&rsquo;s best to check. Still, if you can move something to the compile time, and especially avoid dynamic runtime memory allocations, then it&rsquo;s a clear win.</p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Do you use static variables on a function scope?</li> <li>Have you got any issues or bugs with such variables?</li> </ul> How to Split Ranges in C++23 https://www.cppstories.com/2025/ranges_split_chunk/ Fri, 16 May 2025 00:00:00 +0000 https://www.cppstories.com/2025/ranges_split_chunk/ <p>In this blog post, we&rsquo;ll continue looking at ranges and this time explore ways to split them into sub-ranges. So we&rsquo;ll take a look at <code>views::split</code>, <code>views::chunk</code>, and <code>views::chunk_by</code>.</p> <p>We’ll walk through two examples for each adaptor: one simple and one slightly more advanced, to highlight their practical uses.</p> <p>Let&rsquo;s go.</p> <h2 id="splitting-ranges-with-viewssplit-c20"> Splitting Ranges with <code>views::split</code>, C++20 <a class="hash-link" href="#splitting-ranges-with-viewssplit-c20" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>If you want to split a range using some &ldquo;delimeter,&rdquo; then <code>views::split</code> (or <code>ranges::split_view</code>) will do the job.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span> <span class="n">ranges</span><span class="o">::</span><span class="n">forward_range</span> <span class="n">V</span><span class="p">,</span> <span class="n">ranges</span><span class="o">::</span><span class="n">forward_range</span> <span class="n">Pattern</span> <span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="c1">// .. requires... </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">class</span> <span class="nc">split_vie</span> <span class="o">:</span> <span class="k">public</span> <span class="n">ranges</span><span class="o">::</span><span class="n">view_interface</span><span class="o">&lt;</span><span class="n">split_view</span><span class="o">&lt;</span><span class="n">V</span><span class="p">,</span> <span class="n">Pattern</span><span class="o">&gt;&gt;</span> </span></span></code></pre></div><p>Both of the ranges <code>V</code> and <code>Pattern</code> have to be <code>forward_range</code>.</p> <p>Notice that you need to use a pattern; it cannot be a condition.</p> <h3 id="example-1-splitting-a-sentence-into-words"> Example 1: Splitting a Sentence into Words <a class="hash-link" href="#example-1-splitting-a-sentence-into-words" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string_view&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">string_view_literals</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">text</span> <span class="o">=</span> <span class="s">&#34;C++ is powerful and elegant&#34;</span><span class="n">sv</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">part</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">split</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="sc">&#39; &#39;</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;&#39;{}&#39; &#34;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string_view</span><span class="p">(</span><span class="n">part</span><span class="p">));</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/q9qnvY1rz">@Compiler Explorer</a></p> <p>The output:</p> <pre tabindex="0"><code>&#39;C++&#39; &#39;is&#39; &#39;powerful&#39; &#39;and&#39; &#39;elegant&#39; </code></pre><p>A classic example that splits a sentence into words. We convert each subrange to <code>std::string_view</code> for easy printing.</p> <p>We can also extend this and use not just one character:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="k">auto</span> <span class="n">text</span> <span class="o">=</span> <span class="s">&#34;C++breakisbreakpowerfulbreakandbreakelegant&#34;</span><span class="n">sv</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">part</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">split</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="s">&#34;break&#34;</span><span class="n">sv</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;&#39;{}&#39; &#34;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string_view</span><span class="p">(</span><span class="n">part</span><span class="p">));</span> </span></span></code></pre></div><h3 id="example-2-splitting-not-just-text"> Example 2: Splitting Not Just Text <a class="hash-link" href="#example-2-splitting-not-just-text" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p><code>split</code> can be applied to any forward range, so not just text:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;utility&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">Point</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Point</span><span class="o">&gt;</span> <span class="n">path</span> <span class="o">=</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">},</span> <span class="c1">// marker: {-1, -1} </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">},</span> <span class="p">{</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">},</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">segment</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">split</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">Point</span><span class="p">{</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">}))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Segment: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">segment</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/qqav9M8E7">@Compiler Explorer</a></p> <p>And the output:</p> <pre tabindex="0"><code>Segment: [(0, 0), (1, 1)] Segment: [(2, 2), (3, 3)] Segment: [(4, 4), (5, 5)] </code></pre><p>In the example, we run through the point list and break at markers that are <code>(-1, -1)</code>. This code also leveraged <code>std::format</code> support for ranges (C++23), so we don&rsquo;t have to print individual points.</p> <h2 id="what-about-lazy_split"> What About <code>lazy_split</code>? <a class="hash-link" href="#what-about-lazy_split" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>You might also encounter <code>views::lazy_split</code>, introduced in C++20.</p> <p>This view is specialized for <strong>input-only ranges</strong>, such as reading from streams or generators. It avoids buffering or requiring multiple passes, but its subranges aren’t contiguous and don’t expose <code>.data()</code> or <code>.size()</code>.</p> <p>Unless you’re processing streams in a single pass, prefer <code>views::split</code> for simplicity.</p> <p>Here&rsquo;s a question from Stack Overflow that I recently asked to clarify this view: <a href="https://stackoverflow.com/questions/79621488/what-is-the-use-of-stdrangesviewslazy-split-when-we-have-stdrangesview?noredirect=1#comment140425009_79621488">c++ - What is the use of std::ranges::views::lazy_split when we have std::ranges::views::split? - Stack Overflow</a></p> <h2 id="grouping-with-viewschunk-c23"> Grouping with <code>views::chunk</code>, C++23 <a class="hash-link" href="#grouping-with-viewschunk-c23" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>When you need to process data in fixed-size batches, <code>chunk</code> is the perfect tool.</p> <h3 id="example-1-fixed-size-batches"> Example 1: Fixed-Size Batches <a class="hash-link" href="#example-1-fixed-size-batches" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">data</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">chunk</span> <span class="p">:</span> <span class="n">data</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">chunk</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">chunk</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/136qereK9">@Compiler Explorer</a></p> <p>And the output:</p> <pre tabindex="0"><code>[ 1 2 3 ] [ 4 5 6 ] [ 7 8 ] </code></pre><p><code>views::chunk</code> splits the sequence into groups of three elements. If the number of elements isn’t divisible by 3, the last chunk will contain fewer elements.</p> <h3 id="example-2-processing-network-packets-in-chunks"> Example 2: Processing Network Packets in Chunks <a class="hash-link" href="#example-2-processing-network-packets-in-chunks" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p><code>chunk</code> can work not just with regular containers, but with just input ranges:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sstream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">istringstream</span> <span class="n">stream</span><span class="p">{</span><span class="s">&#34;AB CD EF 12 34 56 78 95 FF&#34;</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">bytes</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">istream_view</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="p">(</span><span class="n">stream</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">packet</span> <span class="p">:</span> <span class="n">bytes</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">chunk</span><span class="p">(</span><span class="mi">4</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Packet: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">packet</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/c1bzT9T16">@Compiler Explorer</a></p> <p>Output:</p> <pre tabindex="0"><code>Packet: [&#34;AB&#34;, &#34;CD&#34;, &#34;EF&#34;, &#34;12&#34;] Packet: [&#34;34&#34;, &#34;56&#34;, &#34;78&#34;, &#34;95&#34;] Packet: [&#34;FF&#34;] </code></pre><p>This example simulates processing a byte stream in fixed 2-byte packets.</p> <h2 id="dynamic-grouping-with-viewschunk_by-c23"> Dynamic Grouping with <code>views::chunk_by</code>, C++23 <a class="hash-link" href="#dynamic-grouping-with-viewschunk_by-c23" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>When the group size isn’t fixed but defined by a condition, <code>chunk_by</code> comes into play. This time, the range has to model forward range at least.</p> <h3 id="example-1-grouping-by-parity-evenodd"> Example 1: Grouping by Parity (Even/Odd) <a class="hash-link" href="#example-1-grouping-by-parity-evenodd" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">values</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">8</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">group</span> <span class="p">:</span> <span class="n">values</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">chunk_by</span><span class="p">([](</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">(</span><span class="n">a</span> <span class="o">%</span> <span class="mi">2</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="n">b</span> <span class="o">%</span> <span class="mi">2</span><span class="p">);</span> <span class="c1">// Same parity </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;size {}, {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">group</span><span class="p">.</span><span class="n">size</span><span class="p">(),</span> <span class="n">group</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/xfoeEK64x">@Compiler Explorer</a></p> <p>Output:</p> <pre tabindex="0"><code>size 3, [1, 3, 5] size 3, [2, 4, 6] size 2, [7, 9] size 1, [8] </code></pre><p>This code dynamically groups consecutive numbers based on their parity. Each group contains either only odd or only even numbers.</p> <h3 id="example-2-extracting-sentences-from-text"> Example 2: Extracting Sentences from Text <a class="hash-link" href="#example-2-extracting-sentences-from-text" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>We can use <code>chunk_by</code> and split at places where a sentence ends.</p> <p>First try:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string_view&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">string_view_literals</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">text</span> <span class="o">=</span> <span class="s">&#34;C++ is powerful. Ranges are elegant. This is fun!&#34;</span><span class="n">sv</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">sentence</span> <span class="p">:</span> <span class="n">text</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">chunk_by</span><span class="p">([](</span><span class="kt">char</span> <span class="n">a</span><span class="p">,</span> <span class="kt">char</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Group until a dot is found; start a new group after &#39;.&#39; </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">return</span> <span class="n">a</span> <span class="o">!=</span> <span class="sc">&#39;.&#39;</span> <span class="o">&amp;&amp;</span> <span class="n">b</span> <span class="o">!=</span> <span class="sc">&#39;.&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Sentence: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">sentence</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>And we get:</p> <pre tabindex="0"><code>Sentence: [&#39;C&#39;, &#39;+&#39;, &#39;+&#39;, &#39; &#39;, &#39;i&#39;, &#39;s&#39;, &#39; &#39;, ...] Sentence: [&#39;.&#39;] Sentence: [&#39; &#39;, &#39;R&#39;, &#39;a&#39;, &#39;n&#39;, &#39;g&#39;, &#39;e&#39;, &#39;s&#39;, ...] Sentence: [&#39;.&#39;] Sentence: [&#39; &#39;, &#39;T&#39;, &#39;h&#39;, &#39;i&#39;, &#39;s&#39;, &#39; &#39;, &#39;i&#39;, ...] </code></pre><p>Probably not the best&hellip; but we can try cleaning the result:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">string_view_literals</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">text</span> <span class="o">=</span> <span class="s">&#34;C++ is powerful. Ranges are elegant. This is fun!&#34;</span><span class="n">sv</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">sentence</span> <span class="p">:</span> <span class="n">text</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">chunk_by</span><span class="p">([](</span><span class="kt">char</span> <span class="n">a</span><span class="p">,</span> <span class="kt">char</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Group until a dot is found; start a new group after &#39;.&#39; </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">return</span> <span class="n">a</span> <span class="o">!=</span> <span class="sc">&#39;.&#39;</span> <span class="o">&amp;&amp;</span> <span class="n">b</span> <span class="o">!=</span> <span class="sc">&#39;.&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Remove leading spaces if any, and skip dots-only groups </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">view</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">string_view</span><span class="p">(</span><span class="o">&amp;*</span><span class="n">sentence</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">distance</span><span class="p">(</span><span class="n">sentence</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="n">view</span><span class="p">.</span><span class="n">remove_prefix</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">min</span><span class="p">(</span><span class="n">view</span><span class="p">.</span><span class="n">find_first_not_of</span><span class="p">(</span><span class="sc">&#39; &#39;</span><span class="p">),</span> <span class="n">view</span><span class="p">.</span><span class="n">size</span><span class="p">()));</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">view</span><span class="p">.</span><span class="n">empty</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">view</span> <span class="o">!=</span> <span class="s">&#34;.&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Sentence: [{}]</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">view</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>And now we get:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Sentence: [C++ is powerful] </span></span><span class="line"><span class="cl">Sentence: [Ranges are elegant] </span></span><span class="line"><span class="cl">Sentence: [This is fun!] </span></span></code></pre></div><p>Experiment <a href="https://godbolt.org/z/8fh9vvM4G">@Compiler Explorer</a></p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <table> <thead> <tr> <th>Feature</th> <th><code>split</code></th> <th><code>chunk</code></th> <th><code>chunk_by</code></th> </tr> </thead> <tbody> <tr> <td>C++ Standard</td> <td>C++20</td> <td>C++23</td> <td>C++23</td> </tr> <tr> <td>Fixed-size groups</td> <td>❌</td> <td>✅</td> <td>❌</td> </tr> <tr> <td>Custom grouping</td> <td>❌</td> <td>❌</td> <td>✅</td> </tr> <tr> <td>Text splitting</td> <td>✅</td> <td>❌</td> <td>❌</td> </tr> </tbody> </table> <p>In this text, we explored various ways to split ranges using <code>split</code>, <code>chunk</code> or <code>chunk_by</code>, we also touched a little bit about <code>lazy_split</code>.</p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Which of these adaptors have you already tried?</li> <li>Which one surprised you the most?</li> </ul> <p>Let me know your thoughts in the comments!</p> Views as Data Members for Custom Iterators https://www.cppstories.com/2025/custom_iter_cpp_20_ranges_views/ Tue, 22 Apr 2025 00:00:00 +0000 https://www.cppstories.com/2025/custom_iter_cpp_20_ranges_views/ <p>In this blog post, we&rsquo;ll write an iterator that works with a vector of vectors. We&rsquo;ll explore a &ldquo;manual&rdquo; version as well as leverage C++20 ranges/views to do the hard work.</p> <h2 id="the-problem-statement"> The problem statement <a class="hash-link" href="#the-problem-statement" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>What&rsquo;s the use case? See this popular interview question (found in DailyCodingProblem: <a href="https://www.dailycodingproblem.com/">https://www.dailycodingproblem.com/</a>)</p> <blockquote> <p>Implement a 2D iterator class. It will be initialized with an array of arrays and should implement the following methods: next() : returns the next element in the array of arrays. If there are no more elements, raise an exception. has_next() : returns whether or not the iterator still has elements left. For example, given the input [[1, 2], [3], [], [4, 5, 6]] , calling next() repeatedly should output 1, 2, 3, 4, 5, 6 .</p> </blockquote> <p>Transforming the problem into C++, we can write the following client code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">input</span> <span class="o">=</span> <span class="p">{{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">},</span> <span class="p">{},</span> <span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">}};</span> </span></span><span class="line"><span class="cl"> <span class="n">TwoDIterator</span> <span class="n">it</span><span class="p">(</span><span class="n">input</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="p">(</span><span class="n">it</span><span class="p">.</span><span class="n">has_next</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} &#34;</span><span class="p">,</span> <span class="n">it</span><span class="p">.</span><span class="n">next</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>The case is to implement <code>TwoDIterator.</code></p> <h2 id="initial-version"> Initial Version <a class="hash-link" href="#initial-version" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The main idea for the iterator is to track the &ldquo;inner&rdquo; position as well as the &ldquo;outer&rdquo;. When the inner position reaches the end of some inner vector, we need to check if we have more vectors to traverse.</p> <p>Here&rsquo;s some basic code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdexcept&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">TwoDIterator</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">Vec2D</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">TwoDIterator</span><span class="p">(</span><span class="k">const</span> <span class="n">Vec2D</span><span class="o">&amp;</span> <span class="n">data</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">:</span> <span class="n">data_</span><span class="p">(</span><span class="n">data</span><span class="p">),</span> <span class="n">outer_</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">inner_</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">advance_to_next_valid</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">bool</span> <span class="nf">has_next</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">outer_</span> <span class="o">&lt;</span> <span class="n">data_</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="nf">next</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">has_next</span><span class="p">())</span> <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">out_of_range</span><span class="p">(</span><span class="s">&#34;No more elements&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">val</span> <span class="o">=</span> <span class="n">data_</span><span class="p">[</span><span class="n">outer_</span><span class="p">][</span><span class="n">inner_</span><span class="p">];</span> </span></span><span class="line"><span class="cl"> <span class="o">++</span><span class="n">inner_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">advance_to_next_valid</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">val</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="n">advance_to_next_valid</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="p">(</span><span class="n">outer_</span> <span class="o">&lt;</span> <span class="n">data_</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">inner_</span> <span class="o">&gt;=</span> <span class="n">data_</span><span class="p">[</span><span class="n">outer_</span><span class="p">].</span><span class="n">size</span><span class="p">())</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="o">++</span><span class="n">outer_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">inner_</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">Vec2D</span><span class="o">&amp;</span> <span class="n">data_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">outer_</span><span class="p">,</span> <span class="n">inner_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">input</span> <span class="o">=</span> <span class="p">{{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">},</span> <span class="p">{},</span> <span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">}};</span> </span></span><span class="line"><span class="cl"> <span class="n">TwoDIterator</span> <span class="n">it</span><span class="p">(</span><span class="n">input</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="p">(</span><span class="n">it</span><span class="p">.</span><span class="n">has_next</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} &#34;</span><span class="p">,</span> <span class="n">it</span><span class="p">.</span><span class="n">next</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/b1bbr9x7M">@Compiler Explorer</a></p> <p>The key part of this solution is the <code>advance_to_next_valid()</code> function. It checks if we can move further and if there are any more vectors in the outer range.</p> <h2 id="applying-ranges-and-views-from-c20"> Applying Ranges and Views from C++20 <a class="hash-link" href="#applying-ranges-and-views-from-c20" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>While the solution works fine, in C++20, we can leverage ranges and views.</p> <p>From my previous article (<a href="https://www.cppstories.com/2025/join_concat_ranges/">How to join or concat ranges, C++26 - C++ Stories</a>) we know that if we have nested ranges, we can use <code>join</code> view to do the flattening:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">nested</span><span class="p">{{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">},</span> <span class="p">{},</span> <span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">}};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">flat</span> <span class="o">=</span> <span class="n">nested</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">join</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="nl">i</span> <span class="p">:</span> <span class="n">flat</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">i</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39; &#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/4Kdd8fePK">@Compiler Explorer</a></p> <p>So the question is how to leverage it in our class? (We want to keep the interface of <code>has_next()</code> and <code>next()</code> as this is our requirement).</p> <h2 id="adding-c20-views-to-our-class"> Adding C++20 Views to our class <a class="hash-link" href="#adding-c20-views-to-our-class" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Conceptually we want to add a <code>join</code> view iterators as a data member to the class <code>TwoDIterator</code>. However, the main issue is that it&rsquo;s relatively complex to specify the correct type of such data members we cannot write:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">VecVecIt</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">flat</span> <span class="o">=</span> <span class="n">nested</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">join</span><span class="p">;</span> <span class="c1">// ?? </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">beg_</span> <span class="o">=</span> <span class="n">flat</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="c1">// ?? </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">end_</span> <span class="o">=</span> <span class="n">flat</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="c1">// ?? </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="c1">// ... </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">};</span> </span></span></code></pre></div><p>Let&rsquo;s try step by step:</p> <ul> <li>We cannot use <code>auto</code> for auto-type deduction for data members; we have to specify the exact type. Later we can initialize those data members in constructors.</li> <li>For simplification we can write <code>using Vec2D = std::vector&lt;std::vector&lt;int&gt;&gt;;</code></li> <li><code>std::ranges::join_view&lt;Vec2D&gt;</code> doesn&rsquo;t work as <code>std::vector</code> isn&rsquo;t a view, and <code>join</code> requires views.</li> </ul> <p>Here&rsquo;s the Clang compiler error:</p> <pre tabindex="0"><code>&lt;source&gt;:33:35: error: constraints not satisfied for class template &#39;join_view&#39; [with _Vp = std::vector&lt;std::vector&lt;int&gt;&gt;] 33 | using JoinView = std::ranges::join_view&lt;Vec2D&gt;; | ^~~~~~~~~~~~~~~~ /opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/16.0.0/../../../../include/c++/16.0.0/ranges:2888:14: note: because &#39;std::vector&lt;std::vector&lt;int&gt;&gt;&#39; does not satisfy &#39;view&#39; 2888 | requires view&lt;_Vp&gt; &amp;&amp; input_range&lt;range_reference_t&lt;_Vp&gt;&gt; </code></pre><p>To &ldquo;convert&rdquo; a vector into a view, we can write:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">ref_view</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">Vec2D</span><span class="o">&gt;</span> </span></span></code></pre></div><p>Now we can combine the previous steps into:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">using</span> <span class="n">Vec2D</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">JoinView</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">join_view</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">ref_view</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">Vec2D</span><span class="o">&gt;&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="n">Iterator</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">iterator_t</span><span class="o">&lt;</span><span class="n">JoinView</span><span class="o">&gt;</span><span class="p">;</span> </span></span></code></pre></div><p>Here&rsquo;s the final class:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdexcept&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">TwoDIteratorJoin</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">Vec2D</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">JoinView</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">join_view</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">ref_view</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">Vec2D</span><span class="o">&gt;&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">Iterator</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">iterator_t</span><span class="o">&lt;</span><span class="n">JoinView</span><span class="o">&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">explicit</span> <span class="nf">TwoDIteratorJoin</span><span class="p">(</span><span class="k">const</span> <span class="n">Vec2D</span><span class="o">&amp;</span> <span class="n">data</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">:</span> <span class="n">flattened_</span><span class="p">(</span><span class="n">data</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">join</span><span class="p">),</span> </span></span><span class="line"><span class="cl"> <span class="n">iter_</span><span class="p">(</span><span class="n">flattened_</span><span class="p">.</span><span class="n">begin</span><span class="p">()),</span> </span></span><span class="line"><span class="cl"> <span class="n">end_</span><span class="p">(</span><span class="n">flattened_</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> <span class="p">{}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="na">[[nodiscard]]</span> <span class="kt">bool</span> <span class="n">has_next</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">iter_</span> <span class="o">!=</span> <span class="n">end_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="na">[[nodiscard]]</span> <span class="kt">int</span> <span class="n">next</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">has_next</span><span class="p">())</span> <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">out_of_range</span><span class="p">(</span><span class="s">&#34;No more elements&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="o">*</span><span class="n">iter_</span><span class="o">++</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">JoinView</span> <span class="n">flattened_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">Iterator</span> <span class="n">iter_</span><span class="p">,</span> <span class="n">end_</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">input</span> <span class="o">=</span> <span class="p">{{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">},</span> <span class="p">{},</span> <span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">}};</span> </span></span><span class="line"><span class="cl"> <span class="n">TwoDIteratorJoin</span> <span class="n">it</span><span class="p">(</span><span class="n">input</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="p">(</span><span class="n">it</span><span class="p">.</span><span class="n">has_next</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} &#34;</span><span class="p">,</span> <span class="n">it</span><span class="p">.</span><span class="n">next</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/qvsTPMzaG">@Compiler Explorer</a></p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In this article, we explored two approaches to implementing a 2D iterator in C++. The first, a manual solution, required us to carefully manage both outer and inner indices to traverse a vector of vectors. While this approach is straightforward and works well, it can become verbose and error-prone as complexity grows.</p> <p>With the advent of C++20, ranges and views offer a much more elegant and expressive alternative. By leveraging <code>std::views::join</code>, we can flatten nested containers and iterate over their elements with minimal boilerplate. The main challenge is specifying the correct types for view-based data members, but once addressed, the resulting code is concise, robust, and easy to maintain.</p> <h4 id="back-to-you"> Back To you </h4> <ul> <li>Do you use Ranges and Views from C++20?</li> <li>Have you ever needed to write a custom iterator?</li> </ul> How to join or concat ranges, C++26 https://www.cppstories.com/2025/join_concat_ranges/ Sun, 16 Mar 2025 00:00:00 +0000 https://www.cppstories.com/2025/join_concat_ranges/ <p>Modern C++ continuously improves its range library to provide more expressive, flexible, and efficient ways to manipulate collections. Traditionally, achieving tasks like concatenation and flattening required manual loops, copying, or custom algorithms. With C++&rsquo;s range adaptors, we now have an elegant and efficient way to process collections lazily without unnecessary allocations.</p> <p>In this post, we will explore three powerful range adaptors introduced in different C++ standards:</p> <ul> <li><code>std::ranges::concat_view</code> (C++26)</li> <li><code>std::ranges::join_view</code> (C++20)</li> <li><code>std::ranges::join_with_view</code> (C++23)</li> </ul> <p>Let&rsquo;s break down their differences, use cases, and examples.</p> <h2 id="stdrangesconcat_view-c26"> <code>std::ranges::concat_view</code> (C++26) <a class="hash-link" href="#stdrangesconcat_view-c26" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The <code>concat_view</code> allows you to concatenate multiple independent ranges into a single sequence. Unlike <code>join_view</code>, it does not require a range of ranges—it simply merges the given ranges sequentially while preserving their structure.</p> <p>In short:</p> <ul> <li>Takes multiple independent ranges as arguments.</li> <li>Supports <strong>random access</strong> if all underlying ranges support it.</li> <li>Allows modification if underlying ranges are writable.</li> <li><strong>Lazy evaluation</strong>: No additional memory allocations.</li> </ul> <p>See the example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;array&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">v1</span><span class="p">{</span><span class="s">&#34;world&#34;</span><span class="p">,</span> <span class="s">&#34;hi&#34;</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">v2</span> <span class="p">{</span> <span class="s">&#34;abc&#34;</span><span class="p">,</span> <span class="s">&#34;xyz&#34;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">arr</span><span class="p">[]{</span><span class="s">&#34;one&#34;</span><span class="p">,</span> <span class="s">&#34;two&#34;</span><span class="p">,</span> <span class="s">&#34;three&#34;</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">v1_rev</span> <span class="o">=</span> <span class="n">v1</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">reverse</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">concat</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">concat</span><span class="p">(</span><span class="n">v1_rev</span><span class="p">,</span> <span class="n">v2</span><span class="p">,</span> <span class="n">arr</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">concat</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#34;hello&#34;</span><span class="p">;</span> <span class="c1">// access and write </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="nl">elem</span> <span class="p">:</span> <span class="n">concat</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} &#34;</span><span class="p">,</span> <span class="n">elem</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See at <a href="https://godbolt.org/z/z1r7WE16j">@Compiler Explorer</a></p> <pre tabindex="0"><code>hello world abc xyz one two three </code></pre><p>The example below shows how to concatenate three ranges, v1 is reversed and then combined with v2 and arr. Notice that we can also access the value at position 0 and update it.</p> <p>And a bit more complex example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;list&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Transaction</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">type</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="kt">double</span> <span class="n">amount</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Transaction</span><span class="o">&gt;</span> <span class="n">bank_transactions</span><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s">&#34;Deposit&#34;</span><span class="p">,</span> <span class="mf">100.0</span><span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s">&#34;Withdraw&#34;</span><span class="p">,</span> <span class="mf">50.0</span><span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s">&#34;Deposit&#34;</span><span class="p">,</span> <span class="mf">200.0</span><span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">list</span><span class="o">&lt;</span><span class="n">Transaction</span><span class="o">&gt;</span> <span class="n">credit_card_transactions</span><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s">&#34;Charge&#34;</span><span class="p">,</span> <span class="mf">75.0</span><span class="p">},</span> <span class="p">{</span><span class="s">&#34;Payment&#34;</span><span class="p">,</span> <span class="mf">50.0</span><span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">filtered_bank</span> <span class="o">=</span> <span class="n">bank_transactions</span> </span></span><span class="line"><span class="cl"> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">filter</span><span class="p">([](</span><span class="k">const</span> <span class="n">Transaction</span><span class="o">&amp;</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">t</span><span class="p">.</span><span class="n">amount</span> <span class="o">&gt;=</span> <span class="mf">100.0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">filtered_credit</span> <span class="o">=</span> <span class="n">credit_card_transactions</span> </span></span><span class="line"><span class="cl"> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">filter</span><span class="p">([](</span><span class="k">const</span> <span class="n">Transaction</span><span class="o">&amp;</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">t</span><span class="p">.</span><span class="n">amount</span> <span class="o">&gt;</span> <span class="mf">60.0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">all_transactions</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">concat</span><span class="p">(</span><span class="n">filtered_bank</span><span class="p">,</span> <span class="n">filtered_credit</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">t</span> <span class="p">:</span> <span class="n">all_transactions</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{} - {}$&#34;</span><span class="p">,</span> <span class="n">t</span><span class="p">.</span><span class="n">type</span><span class="p">,</span> <span class="n">t</span><span class="p">.</span><span class="n">amount</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/a9b8YEqr8">@Compiler Explorer</a></p> <h2 id="stdrangesjoin_view-c20"> <code>std::ranges::join_view</code> (C++20) <a class="hash-link" href="#stdrangesjoin_view-c20" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The <code>join_view</code> is designed for flattening a <strong>single range of ranges</strong> into a single sequence. It removes the structural boundaries between nested ranges.</p> <ul> <li>Works on <strong>a single range of ranges</strong> (e.g., <code>std::vector&lt;std::vector&lt;int&gt;&gt;</code>).</li> <li>Does <strong>not</strong> support <code>operator[]</code> (no random access).</li> <li>Eliminates boundaries between sub-ranges.</li> <li><strong>Lazy evaluation</strong>, avoiding memory copies.</li> </ul> <p>A simple example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">nested</span><span class="p">{{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">},</span> <span class="p">{</span><span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">}};</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">joined</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">join</span><span class="p">(</span><span class="n">nested</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="nl">i</span> <span class="p">:</span> <span class="n">joined</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="n">i</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/1E1ohqe6Y">@Compiler Explorer</a></p> <pre tabindex="0"><code>1 2 3 4 5 6 7 </code></pre><p>Of course, we can have different nested ranges&hellip; and this can be handy for string processing:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;map&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">words</span> <span class="p">{</span> <span class="s">&#34;Hello&#34;</span><span class="p">,</span> <span class="s">&#34;World&#34;</span><span class="p">,</span> <span class="s">&#34;Coding&#34;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// regular: </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">freq</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="o">&amp;</span><span class="nl">w</span> <span class="p">:</span> <span class="n">words</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="o">&amp;</span><span class="nl">c</span> <span class="p">:</span> <span class="n">w</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">freq</span><span class="p">[</span><span class="o">::</span><span class="n">tolower</span><span class="p">(</span><span class="n">c</span><span class="p">)]</span><span class="o">++</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// join: </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">freq2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="o">&amp;</span><span class="nl">c</span> <span class="p">:</span> <span class="n">words</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">join</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">freq2</span><span class="p">[</span><span class="o">::</span><span class="n">tolower</span><span class="p">(</span><span class="n">c</span><span class="p">)]</span><span class="o">++</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="p">[</span><span class="n">key</span><span class="p">,</span> <span class="n">val</span><span class="p">]</span> <span class="o">:</span> <span class="n">freq2</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{} -&gt; {}&#34;</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">val</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/vcE3Kj6ch">@Compiler Explorer</a></p> <p>As you can see, thanks to <code>views_join</code> we can save one nested loop and iterate through a single range of characters.</p> <h2 id="stdrangesjoin_with_view-c23"> <code>std::ranges::join_with_view</code> (C++23) <a class="hash-link" href="#stdrangesjoin_with_view-c23" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The <code>join_with_view</code> works like <code>join_view</code>, but it allows inserting a <strong>delimiter</strong> between flattened sub-ranges.</p> <ul> <li>Works on a <strong>single range of ranges</strong>.</li> <li>Allows specifying a delimiter (single element or a range).</li> <li>Does not support random access.</li> <li><strong>Useful for formatting strings or separating collections</strong>.</li> </ul> <p>See the example below:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string_view&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">to_uppercase</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">word</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">result</span><span class="p">(</span><span class="n">word</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">char</span><span class="o">&amp;</span> <span class="nl">c</span> <span class="p">:</span> <span class="n">result</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">c</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">toupper</span><span class="p">(</span><span class="k">static_cast</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span><span class="p">(</span><span class="n">c</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">result</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span><span class="o">&gt;</span> <span class="n">words</span><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="s">&#34;The&#34;</span><span class="p">,</span> <span class="s">&#34;C++&#34;</span><span class="p">,</span> <span class="s">&#34;ranges&#34;</span><span class="p">,</span> <span class="s">&#34;library&#34;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">words_up</span> <span class="o">=</span> <span class="n">words</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">transform</span><span class="p">(</span><span class="n">to_uppercase</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">joined</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">join_with</span><span class="p">(</span><span class="n">words_up</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string_view</span><span class="p">(</span><span class="s">&#34; &#34;</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">c</span> <span class="p">:</span> <span class="n">joined</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">c</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See at <a href="https://godbolt.org/z/njWhb3Gf3">Compiler Explorer</a></p> <pre tabindex="0"><code>THE C++ RANGES LIBRARY </code></pre><h2 id="comparing-concat_view-join_view-and-join_with_view"> Comparing <code>concat_view</code>, <code>join_view</code>, and <code>join_with_view</code> <a class="hash-link" href="#comparing-concat_view-join_view-and-join_with_view" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <table> <thead> <tr> <th>Feature</th> <th><code>concat_view</code> ✅</th> <th><code>join_view</code> ✅</th> <th><code>join_with_view</code> ✅</th> </tr> </thead> <tbody> <tr> <td><strong>Works on multiple independent ranges?</strong></td> <td>✅</td> <td>❌</td> <td>❌</td> </tr> <tr> <td><strong>Flattens nested ranges?</strong></td> <td>❌</td> <td>✅</td> <td>✅</td> </tr> <tr> <td><strong>Supports separators between sub-ranges?</strong></td> <td>❌</td> <td>❌</td> <td>✅</td> </tr> <tr> <td><strong>Random access support?</strong></td> <td>✅ (if all inputs support it)</td> <td>❌</td> <td>❌</td> </tr> </tbody> </table> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>C++&rsquo;s range adaptors provide efficient ways to manipulate collections without unnecessary copying. Here’s a quick summary of when to use each view:</p> <ul> <li>Use <code>concat_view</code> when merging multiple independent ranges.</li> <li>Use <code>join_view</code> when flattening a range of ranges.</li> <li>Use <code>join_with_view</code> when flattening a range of ranges but needing a separator between elements.</li> </ul> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Do you use ranges?</li> <li>What are your most useful views ald algorithms on ranges?</li> </ul> <p>Share your comments below</p> Details of std::mdspan from C++23 https://www.cppstories.com/2025/cpp23_mdspan/ Thu, 27 Feb 2025 00:00:00 +0000 https://www.cppstories.com/2025/cpp23_mdspan/ <p>In this article, we&rsquo;ll see details of <code>std::mdspan,</code> a new view type tailored to multidimensional data. We&rsquo;ll go through type declaration, creation techniques, and options to customize the internal functionality.</p> <h2 id="type-declaration"> Type declaration <a class="hash-link" href="#type-declaration" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The type is declared in the following way:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span> </span></span><span class="line"><span class="cl"> <span class="k">class</span> <span class="nc">T</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">class</span> <span class="nc">Extents</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">class</span> <span class="nc">LayoutPolicy</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">layout_right</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">class</span> <span class="nc">AccessorPolicy</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">default_accessor</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="k">class</span> <span class="nc">mdspan</span><span class="p">;</span> </span></span></code></pre></div><p>And it has its own header <code>&lt;mdspan&gt;</code>.</p> <p>The main proposal for this feature can be found at <a href="https://wg21.link/P0009">https://wg21.link/P0009</a></p> <p>Following the pattern from <code>std::span</code>, we have a few options to create <code>mdspan</code>: with dynamic or static extent.</p> <p>The key difference is that rather than just one dimension, we can specify multiple. The declaration also gives more options in the form of <code>LayoutPolicy</code> and <code>AccessorPolicy</code>. More on that later.</p> <h3 id="static-extent"> Static Extent <a class="hash-link" href="#static-extent" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">vec</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">extents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="o">&gt;&gt;</span> <span class="n">mat3x3</span> <span class="p">{</span> <span class="n">vec</span><span class="p">.</span><span class="n">data</span><span class="p">()</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;sizeof: {}, rank: {}, ext 0: {}, ext 1: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"><span class="k">sizeof</span><span class="p">(</span><span class="n">mat3x3</span><span class="p">),</span> <span class="n">mat3x3</span><span class="p">.</span><span class="n">rank</span><span class="p">(),</span> <span class="n">mat3x3</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">mat3x3</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span> </span></span></code></pre></div><p>The output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">sizeof: 8, rank: 2, ext 0: 3, ext 1: 3 </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/838v94fWY">@Compiler Explorer</a></p> <h3 id="dynamic-extent"> Dynamic Extent <a class="hash-link" href="#dynamic-extent" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>And the dynamic option:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">mat2x2</span> <span class="p">{</span> <span class="n">vec</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;sizeof: {}, rank: {}, ext 0: {}, ext 1: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"><span class="k">sizeof</span><span class="p">(</span><span class="n">mat2x2</span><span class="p">),</span> <span class="n">mat2x2</span><span class="p">.</span><span class="n">rank</span><span class="p">(),</span> <span class="n">mat2x2</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">mat2x2</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span> </span></span></code></pre></div><p>The output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">sizeof: 24, rank: 2, ext 0: 2, ext 1: 2 </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/Gf1K6rE9c">@Compiler Explorer</a></p> <p>The line:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;&gt;</span> </span></span></code></pre></div><p>Is equivalent:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">extents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dynamic_extents</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dynamic_extents</span><span class="o">&gt;&gt;</span> </span></span></code></pre></div><p>In other words, <code>dextents</code> stands for <code>dynamic extents</code>.</p> <p>And as of C++26, we can also simplify it with <code>std::dims</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dims</span><span class="o">&lt;</span><span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">mat2x2</span> <span class="p">{</span> <span class="n">vec</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span> <span class="p">};</span> </span></span></code></pre></div><h3 id="sizeof-mdspan"> Sizeof mdspan <a class="hash-link" href="#sizeof-mdspan" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>As you can see, similarly to <code>std::span</code>, when the size is known at compile time, the object can be smaller (it doesn&rsquo;t have to store the dynamic size).</p> <p>Run here: <a href="https://godbolt.org/z/Pvnb4E9Mn">@Compiler Explorer</a></p> <h2 id="construction-options"> Construction options <a class="hash-link" href="#construction-options" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Let&rsquo;s review some more options to create <code>mdspan</code>:</p> <h4 id="1-default-constructor"> 1. Default Constructor </h4> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="nf">mdspan</span><span class="p">();</span> </span></span></code></pre></div><p>Example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">1</span><span class="o">&gt;&gt;</span> <span class="n">empty_span</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;is empty {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">empty_span</span><span class="p">.</span><span class="n">empty</span><span class="p">());</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/4fzxbbc1j">@Compiler Explorer</a></p> <h4 id="2-extents-from-variadic-arguments"> 2. Extents From Variadic Arguments </h4> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span> <span class="k">class</span><span class="err">... </span><span class="nc">OtherIndexTypes</span> <span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="k">explicit</span> <span class="n">mdspan</span><span class="p">(</span> <span class="n">data_handle_type</span> <span class="n">p</span><span class="p">,</span> <span class="n">OtherIndexTypes</span><span class="p">...</span> <span class="n">exts</span> <span class="p">);</span> </span></span></code></pre></div><p>Example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">arr</span><span class="p">[</span><span class="mi">12</span><span class="p">]</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">extents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="o">&gt;&gt;</span> <span class="n">span</span><span class="p">(</span><span class="n">arr</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;w: {}, h: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">span</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">span</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">ex</span> <span class="o">=</span> <span class="n">span</span><span class="p">.</span><span class="n">extents</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{}, {}&#34;</span><span class="p">,</span> <span class="n">ex</span><span class="p">.</span><span class="n">rank</span><span class="p">(),</span> <span class="n">ex</span><span class="p">.</span><span class="n">static_extent</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">dspan</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;w: {}, h: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">dspan</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">dspan</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">ex2</span> <span class="o">=</span> <span class="n">dspan</span><span class="p">.</span><span class="n">extents</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{}, {}&#34;</span><span class="p">,</span> <span class="n">ex2</span><span class="p">.</span><span class="n">rank</span><span class="p">(),</span> <span class="n">ex2</span><span class="p">.</span><span class="n">static_extent</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/eM7PTG7af">@Compiler Explorer</a></p> <h4 id="3-extents-from-stdarray"> 3. Extents From <code>std::array</code> </h4> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span> <span class="k">class</span> <span class="nc">OtherIndexType</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">size_t</span> <span class="n">N</span> <span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="k">explicit</span><span class="p">(</span><span class="n">N</span> <span class="o">!=</span> <span class="n">rank_dynamic</span><span class="p">())</span> <span class="n">mdspan</span><span class="p">(</span> <span class="n">data_handle_type</span> <span class="n">p</span><span class="p">,</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="n">OtherIndexType</span><span class="p">,</span> <span class="n">N</span><span class="o">&gt;&amp;</span> <span class="n">exts</span> <span class="p">);</span> </span></span></code></pre></div><p>Example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">arr</span><span class="p">[</span><span class="mi">12</span><span class="p">]</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;</span> <span class="n">my_extents</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">extents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="o">&gt;&gt;</span> <span class="n">span</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">my_extents</span><span class="p">);</span> </span></span></code></pre></div><p>or simpler with CTAD:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span> <span class="n">span</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">my_extents</span><span class="p">);</span> <span class="c1">// but this time extends are dynamic </span></span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/759zje3Yz">@Compiler Explorer</a></p> <h2 id="layout"> Layout <a class="hash-link" href="#layout" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Since we&rsquo;re dealing with multidimensional data, there are a couple of ways we can access elements. That&rsquo;s why we have the &ldquo;layout&rdquo; policy class to represent various options.</p> <p>Here are the basic layouts available as of C++23:</p> <ul> <li><code>layout_right</code>: C or C++ style, row major, where the rightmost index gives stride-1 access to the underlying memory;</li> <li><code>layout_left</code>: Fortran or Matlab style, column major, where the leftmost index gives stride-1 access to the underlying memory;</li> <li><code>layout_stride</code>: a generalization of the two layouts above, which stores a separate stride (possibly not one) for each extent.</li> </ul> <p>Plus, as of C++26, we&rsquo;ll get two more options:</p> <ul> <li><code>layout_left_padded</code> - column-major layout mapping policy with padding stride that can be greater than or equal to the leftmost extent</li> <li><code>layout_right_padded</code> - row-major layout mapping policy with padding stride that can be greater than or equal to the rightmost extent</li> </ul> <p>Here&rsquo;s an example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">layout</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">printMat</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">layout</span><span class="o">&gt;</span> <span class="n">mat</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">mat</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">mat</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} &#34;</span><span class="p">,</span> <span class="n">mat</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">vec</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">layout_right</span><span class="o">&gt;</span> <span class="n">mat</span> <span class="p">{</span> <span class="n">vec</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;right:&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">printMat</span><span class="p">(</span><span class="n">mat</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">layout_left</span><span class="o">&gt;</span> <span class="n">mat_left</span> <span class="p">{</span> <span class="n">vec</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;left:&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">printMat</span><span class="p">(</span><span class="n">mat_left</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/r3q44eEv8">@Compiler Explorer</a></p> <p>The output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">right: </span></span><span class="line"><span class="cl">0 1 2 </span></span><span class="line"><span class="cl">3 4 5 </span></span><span class="line"><span class="cl">left: </span></span><span class="line"><span class="cl">0 2 4 </span></span><span class="line"><span class="cl">1 3 5 </span></span></code></pre></div><p><img src="../images/right_left_layout.png" alt=""></p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><code>std::mdspan</code> provides a powerful and efficient way to interact with multidimensional data, which was a huge pain point for C++. While sometimes it is hard to spell out the full type, <code>mdspan</code> is very flexible and offers many handy ways to work with data.</p> <p>In the text, I also showed how to use layout policy for a different way to order elements in the view. The missing part is &ldquo;AccessorPolicy&rdquo; which is a policy class that specifies how each element is accessed. For example we can implement a &ldquo;checked&rdquo; policy that would ensure the index is not out of range. But I&rsquo;ll leave that for later considerations.</p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Have you played with <code>mdspan</code>?</li> <li>What do you use to work with multidimensional data?</li> </ul> <p>Share your comments below</p> Adjacency Matrix and std::mdspan, C++23 https://www.cppstories.com/2025/cpp23_mdspan_adj/ Tue, 11 Feb 2025 00:00:00 +0000 https://www.cppstories.com/2025/cpp23_mdspan_adj/ <p>In graph theory, an <strong>adjacency matrix</strong> is a square matrix used to represent a finite (and usually dense) graph. The elements of the matrix indicate whether pairs of vertices are adjacent or not, and in weighted graphs, they store the edge weights.</p> <p>In many beginner-level tutorials, adjacency matrices are implemented using <strong>vector of vectors</strong> (nested dynamic arrays), but this approach has inefficiencies due to multiple memory allocations. C++23 introduces <code>std::mdspan</code>, which provides a more efficient way to handle multidimensional data structures without the overhead of nested containers.</p> <p>In this blog post, we&rsquo;ll explore various implementations of an adjacency matrix, starting with a basic approach and progressively improving it using <code>std::mdspan</code>.</p> <h2 id="starting-slow"> Starting slow <a class="hash-link" href="#starting-slow" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Let&rsquo;s start with a straightforward implementation using a <strong>vector of vectors</strong> to represent the adjacency matrix.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;limits&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Graph</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="k">constexpr</span> <span class="n">T</span> <span class="n">INF</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">numeric_limits</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">max</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&gt;</span> <span class="n">adjacencyMatrix</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">numVertices</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">Graph</span><span class="p">(</span><span class="n">size_t</span> <span class="n">vertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">:</span> <span class="n">numVertices</span><span class="p">(</span><span class="n">vertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">,</span> <span class="n">adjacencyMatrix</span><span class="p">(</span><span class="n">vertices</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">vertices</span><span class="p">,</span> <span class="n">INF</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">numVertices</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">adjacencyMatrix</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">addEdge</span><span class="p">(</span><span class="n">size_t</span> <span class="n">u</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">v</span><span class="p">,</span> <span class="n">T</span> <span class="n">weight</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">u</span> <span class="o">&lt;</span> <span class="n">numVertices</span> <span class="o">&amp;&amp;</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="n">numVertices</span> <span class="o">&amp;&amp;</span> <span class="n">u</span> <span class="o">!=</span> <span class="n">v</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">adjacencyMatrix</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">weight</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">adjacencyMatrix</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="n">weight</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">bool</span> <span class="nf">isConnected</span><span class="p">(</span><span class="n">size_t</span> <span class="n">u</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">v</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">(</span><span class="n">u</span> <span class="o">&lt;</span> <span class="n">numVertices</span> </span></span><span class="line"><span class="cl"> <span class="o">&amp;&amp;</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="n">numVertices</span> </span></span><span class="line"><span class="cl"> <span class="o">&amp;&amp;</span> <span class="n">adjacencyMatrix</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&gt;&amp;</span> <span class="n">getAdjacencyMatrix</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">adjacencyMatrix</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">printGraph</span><span class="p">(</span><span class="k">const</span> <span class="n">Graph</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&amp;</span> <span class="n">g</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Adjacency Matrix:</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">row</span> <span class="p">:</span> <span class="n">g</span><span class="p">.</span><span class="n">getAdjacencyMatrix</span><span class="p">())</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">T</span> <span class="nl">weight</span> <span class="p">:</span> <span class="n">row</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">weight</span> <span class="o">==</span> <span class="n">Graph</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">INF</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34; ∞ &#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34; {:3} &#34;</span><span class="p">,</span> <span class="n">weight</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><ul> <li>The class represents an undirected weighted graph.</li> <li>The adjacency matrix is initialized with <code>INF</code> (representing no direct connection between nodes).</li> <li>The diagonal elements are set to <code>0</code> since a node is always connected to itself.</li> <li><code>addEdge</code> ensures bidirectional connections by setting both <code>adjacencyMatrix[u][v]</code> and <code>adjacencyMatrix[v][u]</code>.</li> <li><code>isConnected</code> checks if a direct edge exists between two vertices.</li> </ul> <p>And here&rsquo;s the main function:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Graph</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">g</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">g</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">g</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">g</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">g</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">g</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">g</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">g</span><span class="p">.</span><span class="n">addEdge</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">7</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">printGraph</span><span class="p">(</span><span class="n">g</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;</span><span class="se">\n</span><span class="s">Is node 1 connected to node 3? {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">g</span><span class="p">.</span><span class="n">isConnected</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Is node 0 connected to node 4? {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">g</span><span class="p">.</span><span class="n">isConnected</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">));</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/GG6a9Tsxo">@Compiler Explorer</a></p> <p>Here&rsquo;s a visual representation of this demo graph:</p> <p><img src="../images/demo_graph_adj_mat.png" alt=""></p> <h2 id="improving-efficiency-with-a-single-vector"> Improving Efficiency with a Single Vector <a class="hash-link" href="#improving-efficiency-with-a-single-vector" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Using a vector of vectors is simple but inefficient due to separate memory allocations for each row. Instead, we can use a <strong>single contiguous vector</strong> to store the matrix elements, which improves cache locality and reduces memory fragmentation.</p> <p>See the following code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Graph</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="k">constexpr</span> <span class="n">T</span> <span class="n">INF</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">numeric_limits</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">max</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">adjacencyMatrix</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">numVertices</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="nf">index</span><span class="p">(</span><span class="n">size_t</span> <span class="n">row</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">col</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">row</span> <span class="o">*</span> <span class="n">numVertices</span> <span class="o">+</span> <span class="n">col</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">Graph</span><span class="p">(</span><span class="n">size_t</span> <span class="n">vertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">:</span> <span class="n">numVertices</span><span class="p">(</span><span class="n">vertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">,</span> <span class="n">adjacencyMatrix</span><span class="p">(</span><span class="n">vertices</span> <span class="o">*</span> <span class="n">vertices</span><span class="p">,</span> <span class="n">INF</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">numVertices</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">adjacencyMatrix</span><span class="p">[</span><span class="n">index</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">i</span><span class="p">)]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// ... </span></span></span></code></pre></div><p>Above, we have the function <code>index(row, col)</code> that does the proper indexing.</p> <p>Run <a href="https://godbolt.org/z/W9GWzK3xb">@Compiler Explorer</a></p> <h2 id="c23-md-span"> C++23 MD span <a class="hash-link" href="#c23-md-span" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>C++23 introduces <code>std::mdspan</code>, a lightweight non-owning view over multidimensional data. It allows indexing into a contiguous 1D array as if it were a multidimensional array without needing explicit indexing functions.</p> <p>Here&rsquo;s a basic example of how to use this view type:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;mdspan&gt; // &lt;&lt; new header!</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">isSymmetric</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">matrix</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">rows</span> <span class="o">=</span> <span class="n">matrix</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">cols</span> <span class="o">=</span> <span class="n">matrix</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">rows</span> <span class="o">!=</span> <span class="n">cols</span><span class="p">)</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0u</span><span class="n">z</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">rows</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">j</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">cols</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">matrix</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span> <span class="o">!=</span> <span class="n">matrix</span><span class="p">[</span><span class="n">j</span><span class="p">,</span> <span class="n">i</span><span class="p">])</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">matrix_data</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">matrix</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="p">(</span><span class="n">matrix_data</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">isSymmetric</span><span class="p">(</span><span class="n">matrix</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/37WcPhhzc">@Compiler Explorer</a></p> <p>The key thing is that <code>mdspan</code> is just one object that you pass to a function, and it has all the information and also features to access multidimensional data. Notice the operator <code>[]</code> with two arguments: <code>matrix[i, j]</code>.</p> <p>I must say that the type <code>std::mdspan&lt;int, std::dextents&lt;size_t, 2&gt;&gt; matrix</code> is probably not the nicest to write and spell out, but it wraps all the information in a pretty flexible way.</p> <p>(In C++26, have <code>std::dims</code> helper type that can even make things shorter for dynamic mdspan extents).</p> <h2 id="adjacency-matrix-with-mdspan"> Adjacency Matrix with mdspan <a class="hash-link" href="#adjacency-matrix-with-mdspan" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Thanks to <code>std::mdspan</code>, we can simplify the code to calculate the index. The operator <code>[]</code> can now handle multiple arguments, so it&rsquo;s easy to index into a multidimensional array:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;limits&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;mdspan&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Graph</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="k">constexpr</span> <span class="n">T</span> <span class="n">INF</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">numeric_limits</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">max</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">adjacencyMatrix</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">matrixView</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">numVertices</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">Graph</span><span class="p">(</span><span class="n">size_t</span> <span class="n">vertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">:</span> <span class="n">numVertices</span><span class="p">(</span><span class="n">vertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">,</span> <span class="n">adjacencyMatrix</span><span class="p">(</span><span class="n">vertices</span> <span class="o">*</span> <span class="n">vertices</span><span class="p">,</span> <span class="n">INF</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">,</span> <span class="n">matrixView</span><span class="p">(</span><span class="n">adjacencyMatrix</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="n">vertices</span><span class="p">,</span> <span class="n">vertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">numVertices</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">matrixView</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// copy ctor / move op / assignment... </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">addEdge</span><span class="p">(</span><span class="n">size_t</span> <span class="n">u</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">v</span><span class="p">,</span> <span class="n">T</span> <span class="n">weight</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">u</span> <span class="o">&lt;</span> <span class="n">numVertices</span> <span class="o">&amp;&amp;</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="n">numVertices</span> <span class="o">&amp;&amp;</span> <span class="n">u</span> <span class="o">!=</span> <span class="n">v</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">matrixView</span><span class="p">[</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">weight</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">matrixView</span><span class="p">[</span><span class="n">v</span><span class="p">,</span> <span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="n">weight</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">bool</span> <span class="nf">isConnected</span><span class="p">(</span><span class="n">size_t</span> <span class="n">u</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">v</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">(</span><span class="n">u</span> <span class="o">&lt;</span> <span class="n">numVertices</span> </span></span><span class="line"><span class="cl"> <span class="o">&amp;&amp;</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="n">numVertices</span> </span></span><span class="line"><span class="cl"> <span class="o">&amp;&amp;</span> <span class="n">matrixView</span><span class="p">[</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="nf">getAdjacencyMatrix</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">matrixView</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="nf">getNumVertices</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">numVertices</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">printGraph</span><span class="p">(</span><span class="k">const</span> <span class="n">Graph</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&amp;</span> <span class="n">g</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">n</span> <span class="o">=</span> <span class="n">g</span><span class="p">.</span><span class="n">getNumVertices</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">matrix</span> <span class="o">=</span> <span class="n">g</span><span class="p">.</span><span class="n">getAdjacencyMatrix</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Adjacency Matrix:</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">T</span> <span class="n">weight</span> <span class="o">=</span> <span class="n">matrix</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">];</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">weight</span> <span class="o">==</span> <span class="n">Graph</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">INF</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34; ∞ &#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34; {:3} &#34;</span><span class="p">,</span> <span class="n">weight</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/cM9E6ofbd">@Compiler Explorer</a></p> <h2 id="const-correctness"> Const Correctness <a class="hash-link" href="#const-correctness" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In the previous example, I made a mistake with the member function/getter</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="nf">getAdjacencyMatrix</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">matrixView</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>While the <code>auto</code> as the return type is handy and shortened the code, the issue is that now we can write</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">matrix</span> <span class="o">=</span> <span class="n">g</span><span class="p">.</span><span class="n">getAdjacencyMatrix</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="n">matrix</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1234</span><span class="p">;</span> </span></span></code></pre></div><p>In other words, we return a non-const view of the data, allowing modification of its elements.</p> <p>It&rsquo;s usually not the best approach for getters, and to preserve cost correctness, we should manually specify the return type.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dims</span><span class="o">&lt;</span><span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">getAdjacencyMatrix</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">matrixView</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Now, you can access elements, but you cannot modify them.</p> <h2 id="rule-of-five"> Rule of Five <a class="hash-link" href="#rule-of-five" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Thanks to a valuable comment at <a href="https://www.reddit.com/r/cpp/comments/1iosivl/adjacency_matrix_and_stdmdspan_c23/">Reddit</a>, I&rsquo;ve noticed also another issue:</p> <p>Rule of Five&hellip;</p> <p>Since we introduced a view type as the member of the class, we have to support it through copy/move/assignment operations. Otherwise when you copy a graph object the span will point to a wrong data! See the updated version of the code in the next section.</p> <h2 id="improvements"> Improvements <a class="hash-link" href="#improvements" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The code works, but it&rsquo;s definitely not perfect. Here are some updates we should make:</p> <ul> <li><code>requires std::is_arithmetic_v&lt;T&gt;</code> - the graph class is a template, but we should at least narrow down the &ldquo;weight&rdquo; type that we support.</li> <li>Rule of Zero - checked; see above.</li> <li><code>explicit</code> ctor - to prevent unwanted conversions</li> <li><code>noexcept</code> - at least in some basic functions</li> <li><code>nodiscard</code> - to indicate that a return value should be used, not just thrown away</li> <li>error handling through exceptions</li> </ul> <p>Here&rsquo;s the updated version:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;limits&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;mdspan&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">requires</span> <span class="n">std</span><span class="o">::</span><span class="n">is_arithmetic_v</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Graph</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="k">constexpr</span> <span class="n">T</span> <span class="n">INF</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">numeric_limits</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">max</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">adjacencyMatrix</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dims</span><span class="o">&lt;</span><span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">matrixView</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">numVertices</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">explicit</span> <span class="n">Graph</span><span class="p">(</span><span class="n">size_t</span> <span class="n">vertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">:</span> <span class="n">numVertices</span><span class="p">(</span><span class="n">vertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">,</span> <span class="n">adjacencyMatrix</span><span class="p">(</span><span class="n">vertices</span> <span class="o">*</span> <span class="n">vertices</span><span class="p">,</span> <span class="n">INF</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">,</span> <span class="n">matrixView</span><span class="p">(</span><span class="n">adjacencyMatrix</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="n">vertices</span><span class="p">,</span> <span class="n">vertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">numVertices</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">matrixView</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// copy ctor, move ctor, assignment... </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">addEdge</span><span class="p">(</span><span class="n">size_t</span> <span class="n">u</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">v</span><span class="p">,</span> <span class="n">T</span> <span class="n">weight</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">u</span> <span class="o">&gt;=</span> <span class="n">numVertices</span> <span class="o">||</span> <span class="n">v</span> <span class="o">&gt;=</span> <span class="n">numVertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">out_of_range</span><span class="p">(</span><span class="s">&#34;Vertex index out of bounds&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">u</span> <span class="o">==</span> <span class="n">v</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">invalid_argument</span><span class="p">(</span><span class="s">&#34;Self-loops are not allowed&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">matrixView</span><span class="p">[</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">weight</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">matrixView</span><span class="p">[</span><span class="n">v</span><span class="p">,</span> <span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="n">weight</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="na">[[nodiscard]]</span> <span class="kt">bool</span> <span class="n">isConnected</span><span class="p">(</span><span class="n">size_t</span> <span class="n">u</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">v</span><span class="p">)</span> <span class="k">const</span><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">u</span> <span class="o">&gt;=</span> <span class="n">numVertices</span> <span class="o">||</span> <span class="n">v</span> <span class="o">&gt;=</span> <span class="n">numVertices</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">throw</span> <span class="n">std</span><span class="o">::</span><span class="n">out_of_range</span><span class="p">(</span><span class="s">&#34;Vertex index out of bounds&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">matrixView</span><span class="p">[</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="na">[[nodiscard]]</span> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dims</span><span class="o">&lt;</span><span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">getAdjacencyMatrix</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">matrixView</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="na">[[nodiscard]]</span> <span class="n">size_t</span> <span class="n">getNumVertices</span><span class="p">()</span> <span class="k">const</span> <span class="k">noexcept</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">numVertices</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">printGraph</span><span class="p">(</span><span class="k">const</span> <span class="n">Graph</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&amp;</span> <span class="n">g</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">n</span> <span class="o">=</span> <span class="n">g</span><span class="p">.</span><span class="n">getNumVertices</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">matrix</span> <span class="o">=</span> <span class="n">g</span><span class="p">.</span><span class="n">getAdjacencyMatrix</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Adjacency Matrix:</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">T</span> <span class="n">weight</span> <span class="o">=</span> <span class="n">matrix</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">];</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">weight</span> <span class="o">==</span> <span class="n">Graph</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">INF</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34; ∞ &#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34; {:3} &#34;</span><span class="p">,</span> <span class="n">weight</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/GrbY9Ysbz">@Compiler Explorer</a></p> <h2 id="implementation-notes"> Implementation notes <a class="hash-link" href="#implementation-notes" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The code shown in examples works just great in Clang 18.+! In Compiler Explorer use <code>-stdlib=libc++</code> so that it uses the proper Standard Library implementation.</p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In this article, we discuss a simple and naive implementation of an adjacency graph and enhance it with the latest features from C++23. The use of <code>mdspan</code> facilitates the creation of a proper 2D view over a contiguous sequence of data.</p> <p>The final code is a bit better, but of course, I&rsquo;m happy to see your suggestions and improvements we can make here.</p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Have you played with <code>mdspan</code>?</li> <li>What do you use to work with multidimensional data?</li> </ul> <p>Share your comments below</p> How to use std::span from C++20 https://www.cppstories.com/2023/span-cpp20/ Mon, 03 Feb 2025 00:00:00 +0000 https://www.cppstories.com/2023/span-cpp20/ <p>In this article, we&rsquo;ll look at <code>std::span</code>, which has been available since C++20. This &ldquo;view&rdquo; type is more generic than <code>string_view</code> and can help work with arbitrary contiguous collections.</p> <blockquote class="hint note"> Updated in Feb 2025: added section about returning spans and C++26 improvements (<code>.at()</code> and creatoion from initializer list). </blockquote> <h2 id="a-motivating-example"> A Motivating Example <a class="hash-link" href="#a-motivating-example" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Here&rsquo;s an example that illustrates the primary use case for <code>std::span</code>:</p> <p>In traditional C (or low-level C++), you&rsquo;d pass an array to a function using a pointer and a size like this:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">process_array</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span> <span class="n">arr</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">size_t</span> <span class="n">size</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">size</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// do something with arr[i] </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p><code>std::span</code> simplifies the above code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">process_array</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">arr_span</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span><span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="nl">elem</span> <span class="p">:</span> <span class="n">arr_span</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// do something with elem </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>The need to pass a separate size variable is eliminated, making your code less error-prone and more expressive.</p> <p>And in essence: <code>std::span&lt;T&gt;</code> is:</p> <ul> <li>a lightweight abstraction of a contiguous sequence of values of type T,</li> <li>more or less implemented as <code>struct { T * ptr; std::size_t length; }</code>,</li> <li>a non-owning type (i.e. a &ldquo;reference type&rdquo; rather than a &ldquo;value type&rdquo;).</li> </ul> <h2 id="construction-of-stdspan"> Construction of <code>std::span</code> <a class="hash-link" href="#construction-of-stdspan" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><code>std::span</code> lives in its own new header <code>&lt;span&gt;</code>. It&rsquo;s defined as follows:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">size_t</span> <span class="n">Extent</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">dynamic_extent</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">span</span><span class="p">;</span> </span></span></code></pre></div><p>To create this object, you have two basic options: static extent and dynamic:</p> <h3 id="static-extent"> Static Extent <a class="hash-link" href="#static-extent" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>When you know the size at compile-time:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">5</span><span class="o">&gt;</span> <span class="n">arr_span</span> <span class="p">{</span><span class="n">arr</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="c1">//std::span&lt;int, 2&gt; arr_span2 {arr}; // error size doesn&#39;t match </span></span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/1ejcP39Ms">@Compiler Explorer</a></p> <p>Here, the <code>5</code> is an integral part of the type. You&rsquo;ll get a compiler error if you try to initialize this span with an array of different sizes.</p> <h3 id="dynamic-extent"> Dynamic Extent <a class="hash-link" href="#dynamic-extent" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>When you only know the size at runtime, like when working with vectors:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span> <span class="n">v</span> <span class="p">{</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">arr_span</span> <span class="p">{</span><span class="n">arr</span><span class="p">};</span> <span class="c1">// dynamic extent </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">vec_span</span> <span class="p">{</span><span class="n">v</span><span class="p">};</span> <span class="c1">// also! </span></span></span></code></pre></div><p>See <a href="https://godbolt.org/z/K7d6q8Mdq">@Compiler Explorer</a></p> <p>Notice the absence of size in the type? That&rsquo;s the dynamic extent in action.</p> <h3 id="sizeof-span"> Sizeof span <a class="hash-link" href="#sizeof-span" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>The interesting part about <code>span</code> is that when the size is static, then the type is smaller as there&rsquo;s no need to store the size of the sequence:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">vec</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">5</span><span class="o">&gt;</span> <span class="n">arr_span</span> <span class="p">{</span><span class="n">arr</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">other_span</span> <span class="p">{</span><span class="n">arr</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">vec_span</span><span class="p">{</span><span class="n">vec</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&#34;sizeof arr_span: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">arr_span</span><span class="p">));</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&#34;sizeof other_span: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">other_span</span><span class="p">));</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&#34;sizeof vec_span: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">vec_span</span><span class="p">));</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/79Gvjzzzs">@Compiler Explorer</a></p> <p>The output on GCC is:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">sizeof arr_span: 8 </span></span><span class="line"><span class="cl">sizeof other_span: 16 </span></span><span class="line"><span class="cl">sizeof vec_span: 16 </span></span></code></pre></div><h3 id="more-construction-options"> More construction options <a class="hash-link" href="#more-construction-options" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>For completeness, let&rsquo;s now revise other construction options following the list of available constructors:</p> <div style="width:82%;background-color:var(--background-light1-color);border-top:solid 1px #FF7E00;border-bottom:solid 1px #FF7E00;margin-left:auto;margin-right:auto;"> <p style="text-align:justify;margin: 0.5em;"> This article started as a preview for Patrons, sometimes even months before the publication. If you want to get extra content, previews, free ebooks and access to our Discord server, join <a href="https://www.patreon.com/cppstories" target="_blank"><strong>the C++ Stories Premium membership</strong></a> or see <a href="https://www.cppstories.com/p/extra-patreon-content/" target="_blank">more information.</a> </p> </div> <h3 id="default-constructor"> Default Constructor <a class="hash-link" href="#default-constructor" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>This constructs an empty span.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">empty_span</span><span class="p">;</span> </span></span></code></pre></div><p><code>.data()</code> returns <code>nullptr</code> and the <code>size()</code> returns <code>0</code> in this case.</p> <h3 id="from-iterators-and-size"> From Iterators and Size <a class="hash-link" href="#from-iterators-and-size" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Creates a span from a starting iterator and a size.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">vec</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">from_iterator_and_size</span><span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="cm">/*count*/</span><span class="mi">2</span><span class="p">);</span> <span class="c1">// 1, 2 </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">from_iterator_and_size2</span><span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="cm">/*count*/</span><span class="mi">3</span><span class="p">);</span> <span class="c1">// 1, 2, 3 </span></span></span></code></pre></div><p>And also in CTAD version:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span> <span class="n">vec</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span> <span class="n">from_iterator_and_size</span><span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="cm">/*count*/</span><span class="mi">2</span><span class="p">);</span> <span class="c1">// 1, 2 </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span> <span class="n">from_iterator_and_size2</span><span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="cm">/*count*/</span><span class="mi">3</span><span class="p">);</span> <span class="c1">// 1, 2, 3 </span></span></span></code></pre></div><p>See <a href="https://godbolt.org/z/xbvMxM915">@Compiler Explorer</a></p> <h3 id="from-two-iterators"> From Two Iterators <a class="hash-link" href="#from-two-iterators" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Constructs a span from a range specified by two iterators.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">from_two_iterators</span><span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">vec</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> </span></span></code></pre></div><p>And using CTAD:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span> <span class="n">from_iterator_and_end</span><span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">vec</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/jbhbKEK6q">@Compiler Explorer</a></p> <h3 id="from-c-style-array"> From C-style Array <a class="hash-link" href="#from-c-style-array" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>For C-style arrays.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">from_array</span><span class="p">(</span><span class="n">arr</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span> <span class="n">from_array2</span><span class="p">(</span><span class="n">arr</span><span class="p">);</span> </span></span></code></pre></div><p><code>.data()</code> returns <code>std::data(arr)</code></p> <p>See <a href="https://godbolt.org/z/nWxY8Tcqb">@Compiler Explorer</a></p> <h3 id="from-stdarray"> From <code>std::array</code> <a class="hash-link" href="#from-stdarray" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Can construct both from non-const and const <code>std::array</code>.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">3</span><span class="o">&gt;</span> <span class="n">std_arr</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">3</span><span class="o">&gt;</span> <span class="n">from_std_array</span><span class="p">(</span><span class="n">std_arr</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="c1">// CTAD: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">span</span> <span class="n">from_std_array2</span><span class="p">(</span><span class="n">std_arr</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">3</span><span class="o">&gt;</span> <span class="n">const_std_arr</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">from_const_std_array</span><span class="p">(</span><span class="n">const_std_arr</span><span class="p">);</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/4fazYhKG3">@Compiler Explorer</a></p> <h3 id="from-contiguous-range"> From Contiguous Range <a class="hash-link" href="#from-contiguous-range" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Using this constructor, you can pass in any contiguous range like <code>std::vector</code>.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span> <span class="n">vec</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">from_range</span><span class="p">(</span><span class="n">vec</span><span class="p">);</span> <span class="c1">// covers entire vec </span></span></span><span class="line"><span class="cl"><span class="c1">// CTAD: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">span</span> <span class="n">from_range2</span><span class="p">(</span><span class="n">vec</span><span class="p">);</span><span class="n">ec</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/v4ea3c65h">@Compiler Explorer</a></p> <h3 id="conversion-from-another-span"> Conversion from Another Span <a class="hash-link" href="#conversion-from-another-span" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Can be used for type conversions if the types are compatible.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">int_span</span><span class="p">(</span><span class="n">vec</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">const_span</span> <span class="o">=</span> <span class="n">int_span</span><span class="p">;</span> <span class="c1">// conversion </span></span></span></code></pre></div><h2 id="passing-spans"> Passing spans <a class="hash-link" href="#passing-spans" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Spans are lightweight objects intended to pass by value. But we have two options to preserve the constness of its elements:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">print</span><span class="p">(</span><span class="n">span</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="n">outbuf</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">transform</span><span class="p">(</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">inbuf</span><span class="p">);</span> </span></span></code></pre></div><p>In other words, you can pass <code>span&lt;const T&gt;</code> to indicate constant elements, and &ldquo;read only&rdquo; access, or pass <code>span&lt;T&gt;</code> to allow read/write access.</p> <p>For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">transform</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">outbuf</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="nl">elem</span> <span class="p">:</span> <span class="n">outbuf</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">elem</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">output</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="n">outbuf</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;contents: &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="nl">elem</span> <span class="p">:</span> <span class="n">outbuf</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">elem</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;, &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="c1">// elem = 0; // error! </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">str</span> <span class="o">=</span> <span class="s">&#34;Hello World&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">buf_span</span><span class="p">(</span><span class="n">str</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">output</span><span class="p">(</span><span class="n">str</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">transform</span><span class="p">(</span><span class="n">buf_span</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">output</span><span class="p">(</span><span class="n">buf_span</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/T9jxxqfjd">@Compiler Explorer</a></p> <p>The output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">contents: H, e, l, l, o, , W, o, r, l, d, </span></span><span class="line"><span class="cl">contents: I, f, m, m, p, !, X, p, s, m, e, </span></span></code></pre></div><p>The example above shows that <code>str</code> nicely converts into a span and is passed to the <code>output</code> function. And later, the <code>buf_span</code> is also converted (<code>char</code> to <code>const char</code>) when passing to <code>output</code>.</p> <h2 id="subspans"> Subspans <a class="hash-link" href="#subspans" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>You can easily create subviews/subspans of existing spans:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">printSpan</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">sp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="nl">elem</span> <span class="p">:</span> <span class="n">sp</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">elem</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39; &#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">sp</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="mi">6</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// subspan(start, count): </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">sub</span> <span class="o">=</span> <span class="n">sp</span><span class="p">.</span><span class="n">subspan</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="cm">/*count*/</span><span class="mi">2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">printSpan</span><span class="p">(</span><span class="n">sub</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// fist(count): </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">subFirst3</span> <span class="o">=</span> <span class="n">sp</span><span class="p">.</span><span class="n">first</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">printSpan</span><span class="p">(</span><span class="n">subFirst3</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// last(count): </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">subLast4</span> <span class="o">=</span> <span class="n">sp</span><span class="p">.</span><span class="n">last</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">printSpan</span><span class="p">(</span><span class="n">subLast4</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/bbx6srn7z">@Compiler Explorer</a></p> <p>The output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">3 4 </span></span><span class="line"><span class="cl">1 2 3 </span></span><span class="line"><span class="cl">3 4 5 6 </span></span></code></pre></div><h2 id="showing-basic-properties"> Showing basic properties <a class="hash-link" href="#showing-basic-properties" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Here&rsquo;s another example that prints basic information about spans:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">vec</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">array</span> <span class="n">sarr</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">5</span><span class="o">&gt;</span> <span class="n">arr_span</span> <span class="p">{</span><span class="n">arr</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">sarr_span</span> <span class="p">{</span><span class="n">arr</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">vec_span</span><span class="p">{</span><span class="n">vec</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">span_info</span> <span class="o">=</span> <span class="p">[](</span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">str</span><span class="p">,</span> <span class="k">auto</span> <span class="n">sp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&#34;{}</span><span class="se">\n</span><span class="s"> sizeof {}</span><span class="se">\n</span><span class="s"> extent {}</span><span class="se">\n</span><span class="s"> size in bytes: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">str</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">sp</span><span class="p">),</span> <span class="n">sp</span><span class="p">.</span><span class="n">extent</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">dynamic_extent</span> <span class="o">?</span> <span class="s">&#34;dynamic&#34;</span> <span class="o">:</span> <span class="s">&#34;static&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">sp</span><span class="p">.</span><span class="n">size_bytes</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">span_info</span><span class="p">(</span><span class="s">&#34;arr_span&#34;</span><span class="p">,</span> <span class="n">arr_span</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">span_info</span><span class="p">(</span><span class="s">&#34;sarr_span&#34;</span><span class="p">,</span> <span class="n">sarr_span</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">span_info</span><span class="p">(</span><span class="s">&#34;vec_span&#34;</span><span class="p">,</span> <span class="n">vec_span</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/v7Evj6WYY">@Compiler Explorer</a></p> <p>The output from GCC:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">arr_span </span></span><span class="line"><span class="cl"> sizeof 8 </span></span><span class="line"><span class="cl"> extent static </span></span><span class="line"><span class="cl"> size in bytes: 20 </span></span><span class="line"><span class="cl">sarr_span </span></span><span class="line"><span class="cl"> sizeof 16 </span></span><span class="line"><span class="cl"> extent dynamic </span></span><span class="line"><span class="cl"> size in bytes: 20 </span></span><span class="line"><span class="cl">vec_span </span></span><span class="line"><span class="cl"> sizeof 16 </span></span><span class="line"><span class="cl"> extent dynamic </span></span><span class="line"><span class="cl"> size in bytes: 20 </span></span></code></pre></div><h2 id="c26-spanat"> C++26 <code>span::at()</code> <a class="hash-link" href="#c26-spanat" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>With C++26, <code>std::span</code> gains the <code>at()</code> method, which provides bounds-checked access to elements, similar to <code>std::vector::at()</code>. This ensures safer indexing by throwing <code>std::out_of_range</code> if an invalid index is accessed.</p> <p>Have a look:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;span&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdexcept&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">span</span> <span class="o">=</span> <span class="n">data</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Element at index 2: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">span</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Trying to access index 10...</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">span</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">out_of_range</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Exception caught: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/1cMhMdqjv">@Compiler Explorer</a></p> <p>Key benefits of this new feature:</p> <ul> <li><strong>Safety</strong>: Prevents undefined behavior by ensuring out-of-bounds access throws an exception.</li> <li><strong>Consistency</strong>: Aligns <code>std::span</code> with other standard containers (<code>std::vector</code>, <code>std::array</code>, etc.) that already have <code>at()</code>.</li> <li><strong>Debugging Aid</strong>: Makes debugging easier by immediately identifying invalid accesses.</li> </ul> <h2 id="c26-span-over-an-initializer-list"> C++26 span over an initializer list <a class="hash-link" href="#c26-span-over-an-initializer-list" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>With C++26, <code>std::span</code> can now be constructed from an <code>std::initializer_list</code>, closing a gap that previously existed between <code>std::vector</code> and <code>std::span</code> as function parameters. The change comes from the following proposal: <a href="https://wg21.link/P2447">P2447</a></p> <p>While <code>std::string_view</code> can be constructed directly from a string literal, <code>std::span&lt;const T&gt;</code> couldn’t be constructed from a braced initializer list <code>{1, 2, 3}</code>. This led to inconsistencies when using spans in function parameters.</p> <p>Consider this example before C++26:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">process</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">sp</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">process</span><span class="p">({</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">});</span> <span class="c1">// Error: No viable conversion </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">process</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">});</span> <span class="c1">// OK but unnecessary allocation </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">process</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">}));</span> <span class="c1">// Works but verbose </span></span></span></code></pre></div><h4 id="the-c26-solution"> The C++26 Solution </h4> <p>With C++26, <code>std::span&lt;const T&gt;</code> now has a constructor accepting <code>std::initializer_list&lt;T&gt;</code>, allowing direct usage of braced initializer lists:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">process</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">sp</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">process</span><span class="p">({</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">});</span> <span class="c1">// Now works in C++26! </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">process</span><span class="p">({});</span> <span class="c1">// Also works, creating an empty span </span></span></span></code></pre></div><p>This makes <code>std::span&lt;const T&gt;</code> a better drop-in replacement for <code>const std::vector&lt;T&gt;&amp;</code> in function parameters, improving usability and reducing unnecessary copies.</p> <p>See the full example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;span&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">process</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">sp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;sp size is {}&#34;</span><span class="p">,</span> <span class="n">sp</span><span class="p">.</span><span class="n">size</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">process</span><span class="p">(</span><span class="n">data</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">process</span><span class="p">({</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">});</span> <span class="c1">// Now works in C++26! </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">process</span><span class="p">({});</span> <span class="c1">// Also works, creating an empty span </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span></code></pre></div><p>Check at <a href="https://godbolt.org/z/PMhnvon35">Compiler Explorer</a></p> <h4 id="important-notes-on-dangling"> Important Notes on Dangling </h4> <p>Just like <code>std::string_view</code>, <code>std::span</code> does <strong>not</strong> extend the lifetime of temporary data. If used incorrectly, it can lead to dangling references:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">sp</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> <span class="c1">// Dangles! The initializer list is a temporary. </span></span></span></code></pre></div><p>This means <code>std::span</code> over an initializer list is best used for function parameters, where the span is only needed within the function&rsquo;s scope.</p> <h2 id="returning-stdspan"> Returning <code>std::span</code> <a class="hash-link" href="#returning-stdspan" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>While spans are great as input parameters, they can also show their strength as a return type. This can be a middle ground between references and copies, with additional flexibility for handling missing values.</p> <p>Consider the following example, where there&rsquo;s a config manager, and we return a <code>Config</code> using <code>getConfig</code> member function:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;span&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;map&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ConfigManager</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;&gt;</span> <span class="n">configs</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">ConfigManager</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">configs</span><span class="p">[</span><span class="s">&#34;database&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="sc">&#39;h&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;s&#39;</span><span class="p">,</span><span class="sc">&#39;t&#39;</span><span class="p">,</span><span class="sc">&#39;=&#39;</span><span class="p">,</span><span class="sc">&#39;l&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;c&#39;</span><span class="p">,</span><span class="sc">&#39;a&#39;</span><span class="p">,</span><span class="sc">&#39;l&#39;</span><span class="p">,</span><span class="sc">&#39;h&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;s&#39;</span><span class="p">,</span><span class="sc">&#39;t&#39;</span><span class="p">,</span><span class="sc">&#39;;&#39;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="sc">&#39;p&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;r&#39;</span><span class="p">,</span><span class="sc">&#39;t&#39;</span><span class="p">,</span><span class="sc">&#39;=&#39;</span><span class="p">,</span><span class="sc">&#39;5&#39;</span><span class="p">,</span><span class="sc">&#39;4&#39;</span><span class="p">,</span><span class="sc">&#39;3&#39;</span><span class="p">,</span><span class="sc">&#39;2&#39;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">uint8_t</span><span class="o">&gt;</span> <span class="n">getConfig</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">configs</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">name</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">it</span> <span class="o">!=</span> <span class="n">configs</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{};</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">ConfigManager</span> <span class="n">manager</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">dbConfig</span> <span class="o">=</span> <span class="n">manager</span><span class="p">.</span><span class="n">getConfig</span><span class="p">(</span><span class="s">&#34;database&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">byte</span> <span class="p">:</span> <span class="n">dbConfig</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">(</span><span class="n">byte</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">errCfg</span> <span class="o">=</span> <span class="n">manager</span><span class="p">.</span><span class="n">getConfig</span><span class="p">(</span><span class="s">&#34;error&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">byte</span> <span class="p">:</span> <span class="n">errCfg</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">(</span><span class="n">byte</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/q4GsG66cn">@Compiler Explorer</a></p> <p>By using <code>span</code> we can clearly indicate a &ldquo;view&rdquo; type. Additionally, spans support many containers, so even if we change the internal representation of the config entry, we can still return a span object (assuming it&rsquo;s still contiguous&hellip;).</p> <p>Without spans, I&rsquo;d had to return a reference to a vector, which might be tricky when there&rsquo;s no entry found. See my other article about this issue: <a href="https://www.cppstories.com/2025/cpp26-safety-temp/">Improving Code Safety in C++26: Managers and Dangling References - C++ Stories</a>.</p> <h2 id="advantages-of-using-stdspan"> Advantages of Using <code>std::span</code> <a class="hash-link" href="#advantages-of-using-stdspan" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li><strong>Performance</strong>: Like references, spans avoid unnecessary copies.</li> <li><strong>Safety</strong>: Being non-owning, spans make it clear that the caller doesn’t own the data.</li> <li><strong>Interoperability</strong>: Works seamlessly with other container types like <code>std::array</code> or raw arrays.</li> <li><strong>Simpler handling of missing data</strong>: Unlike returning a <code>const std::vector&amp;</code>, where you must return a valid reference, <code>std::span</code> can simply return an empty span (<code>{}</code>).</li> </ul> <h2 id="comparing-with-stdstring_view"> Comparing with <code>std::string_view</code> <a class="hash-link" href="#comparing-with-stdstring_view" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ol> <li><strong>Generality</strong>: <code>std::span</code> can be used with any type, not just character types.</li> <li><strong>Mutability</strong>: Unlike <code>std::string_view</code>, a <code>std::span</code> can modify the data it views (unless you define it as a span of const).</li> <li><strong>Extent</strong>: <code>std::span</code> can have either static or dynamic extent, <code>string_view</code> is always &ldquo;dynamic&rdquo;.</li> </ol> <h2 id="guidelines"> Guidelines <a class="hash-link" href="#guidelines" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Some of the guidelines related to spans:</p> <ul> <li><a href="https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i13-do-not-pass-an-array-as-a-single-pointer">I.13: Do not pass an array as a single pointer</a></li> <li><a href="https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f24-use-a-spant-or-a-span_pt-to-designate-a-half-open-sequence">F.24: Use a span or a span_p to designate a half-open sequence</a></li> <li><a href="https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r14-avoid--parameters-prefer-span">R.14: Avoid <code>[]</code> parameters, prefer span</a></li> <li><a href="https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es42-keep-use-of-pointers-simple-and-straightforward">ES.42: Keep use of pointers simple and straightforward</a></li> </ul> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In this article we looked at <code>std::span</code> introduced in C++20. This type offers a handy way to work with contiguous sequences like arrays or containers. We can say that it&rsquo;s a more generic approach than <code>std::string_view</code> as it allows read/write access (if needed).</p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Have you tried <code>std::span</code>?</li> <li>Do you use other &ldquo;Reference&rdquo;/view types from the Standard Library?</li> </ul> <p>Share your comments below.</p> Improving Code Safety in C++26: Managers and Dangling References https://www.cppstories.com/2025/cpp26-safety-temp/ Mon, 20 Jan 2025 00:00:00 +0000 https://www.cppstories.com/2025/cpp26-safety-temp/ <p>In this blog post, we’ll explore ways to improve the safety of a simple configuration manager. We&rsquo;ll handle common pitfalls like dangling references and excessive stack usage. Additionally, we&rsquo;ll see how C++26 helps enforce safer coding practices with stricter diagnostics and improved handling of large objects.</p> <p>Let’s go.</p> <h2 id="step-1-the-buggy-implementation"> Step 1: The Buggy Implementation <a class="hash-link" href="#step-1-the-buggy-implementation" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Below is a simple example of a manager object that stores various configs in a map and provides a method to retrieve them. When a requested configuration isn’t found, the code attempts to return a default certificate:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;map&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;cstdint&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ConfigManager</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;&gt;</span> <span class="n">configs</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">ConfigManager</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">configs</span><span class="p">[</span><span class="s">&#34;database&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="sc">&#39;h&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;s&#39;</span><span class="p">,</span><span class="sc">&#39;t&#39;</span><span class="p">,</span><span class="sc">&#39;=&#39;</span><span class="p">,</span><span class="sc">&#39;l&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;c&#39;</span><span class="p">,</span><span class="sc">&#39;a&#39;</span><span class="p">,</span><span class="sc">&#39;l&#39;</span><span class="p">,</span><span class="sc">&#39;h&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;s&#39;</span><span class="p">,</span><span class="sc">&#39;t&#39;</span><span class="p">,</span><span class="sc">&#39;;&#39;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="sc">&#39;p&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;r&#39;</span><span class="p">,</span><span class="sc">&#39;t&#39;</span><span class="p">,</span><span class="sc">&#39;=&#39;</span><span class="p">,</span><span class="sc">&#39;5&#39;</span><span class="p">,</span><span class="sc">&#39;4&#39;</span><span class="p">,</span><span class="sc">&#39;3&#39;</span><span class="p">,</span><span class="sc">&#39;2&#39;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;&amp;</span> <span class="n">findConfig</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">configs</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">name</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">it</span> <span class="o">!=</span> <span class="n">configs</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{</span><span class="mi">42</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">ConfigManager</span> <span class="n">configManager</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;&amp;</span> <span class="n">dbConfig</span> <span class="o">=</span> <span class="n">configManager</span><span class="p">.</span><span class="n">findConfig</span><span class="p">(</span><span class="s">&#34;database&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Database config: &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">uint8_t</span> <span class="nl">byte</span> <span class="p">:</span> <span class="n">dbConfig</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">(</span><span class="n">byte</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/e1Yc7K69b">@Compiler Explorer</a></p> <p>Do you see a potential error in this code?</p> <p>. . .</p> <p>At first glance, the code looks harmless. However, if the requested entry isn’t found, the function returns a reference to a temporary <code>std::vector</code>. Once the function exits, that temporary is destroyed—leaving you with a dangling reference and undefined behavior.</p> <h3 id="compiler-warnings"> Compiler Warnings <a class="hash-link" href="#compiler-warnings" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Ok, the bug was easy&hellip; and compilers have warned about this case for a long time.</p> <p>While this is helpful, it’s still possible to overlook or disable the warning, especially if your project is large.</p> <p>So let&rsquo;s try enabling C++26 mode&hellip; for example on GCC 14 you&rsquo;ll get:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">error: returning reference to temporary [-Wreturn-local-addr] </span></span></code></pre></div><p>Great!</p> <p>Now, we cannot skip that error, and we have to fix it.</p> <p>This handy features comes from: Disallow binding a returned reference to a temporary <a href="https://wg21.link/P2748R5">P2748R5</a> - implemented in GCC 14 and Clang 19.</p> <h2 id="step-2-fixing-the-dangling-reference"> Step 2: Fixing the Dangling Reference <a class="hash-link" href="#step-2-fixing-the-dangling-reference" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>One straightforward fix is to ensure that the &ldquo;default config&rdquo; has a lifetime extending beyond the function scope. A static object does the trick:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ConfigManager</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;&gt;</span> <span class="n">configs</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;&amp;</span> <span class="n">getDefaultConfig</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;</span> <span class="n">def</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">def</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">ConfigManager</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">configs</span><span class="p">[</span><span class="s">&#34;database&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="sc">&#39;h&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;s&#39;</span><span class="p">,</span><span class="sc">&#39;t&#39;</span><span class="p">,</span><span class="sc">&#39;=&#39;</span><span class="p">,</span><span class="sc">&#39;l&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;c&#39;</span><span class="p">,</span><span class="sc">&#39;a&#39;</span><span class="p">,</span><span class="sc">&#39;l&#39;</span><span class="p">,</span><span class="sc">&#39;h&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;s&#39;</span><span class="p">,</span><span class="sc">&#39;t&#39;</span><span class="p">,</span><span class="sc">&#39;;&#39;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="sc">&#39;p&#39;</span><span class="p">,</span><span class="sc">&#39;o&#39;</span><span class="p">,</span><span class="sc">&#39;r&#39;</span><span class="p">,</span><span class="sc">&#39;t&#39;</span><span class="p">,</span><span class="sc">&#39;=&#39;</span><span class="p">,</span><span class="sc">&#39;5&#39;</span><span class="p">,</span><span class="sc">&#39;4&#39;</span><span class="p">,</span><span class="sc">&#39;3&#39;</span><span class="p">,</span><span class="sc">&#39;2&#39;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;&amp;</span> <span class="n">findConfig</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">configs</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">name</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">it</span> <span class="o">!=</span> <span class="n">configs</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nf">getDefaultConfig</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">ConfigManager</span> <span class="n">configManager</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;&amp;</span> <span class="n">dbConfig</span> <span class="o">=</span> <span class="n">configManager</span><span class="p">.</span><span class="n">findConfig</span><span class="p">(</span><span class="s">&#34;database&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Database config: &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">uint8_t</span> <span class="nl">byte</span> <span class="p">:</span> <span class="n">dbConfig</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">(</span><span class="n">byte</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/Yz9K1s6ox">@Compiler Explorer</a></p> <p>By returning a static object from <code>getDefaultConfig</code>, we avoid dangling references and undefined behavior. The object’s lifetime is the entire duration of the program, so it&rsquo;s perfectly safe to return a reference to it.</p> <p>Just to note: this solution isn&rsquo;t perfect, and we could explore another approach, such as using <code>std::optional</code>,<code>std::expected</code> or <code>std::span</code>. But I&rsquo;ll leave that for you as a homework assignment :)</p> <p>The error is now gone, and our program works fine.</p> <p>But&hellip;</p> <h2 id="step-3-the-stack-overflow-problem"> Step 3: The Stack Overflow Problem <a class="hash-link" href="#step-3-the-stack-overflow-problem" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Now, consider what happens if requirements change, and the default config has to contain some large data, for example, a binary representation of some image&hellip; If it is substantial - say around 1&hellip;2MB of data. Storing such a large object in a single vector might look like this:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;&amp;</span> <span class="n">getDefaultConfig</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;</span> <span class="n">def</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// 1, 2, 3, ... </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// in total it&#39;s 2MB of data </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">def</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>This seemingly harmless code can risk <strong>stack overflow</strong>, especially on systems with limited stack space.</p> <p>Why is that? The object is <code>static</code>, so it shouldn&rsquo;t take stack&rsquo;s space&hellip;</p> <p>However, the issue is that we used the initializer list to initialize the vector. Before C++26 the compiler creates a helper array, on the stack, and then copies the data to the vector.</p> <p>See at C++Insights: <a href="https://cppinsights.io/s/85f708c6">https://cppinsights.io/s/85f708c6</a>, the function might be transformed into something like this:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"> <span class="k">static</span> <span class="kr">inline</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span> <span class="o">&amp;</span> <span class="n">getDefaultConfig</span><span class="p">()</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">__list12_41</span><span class="p">[</span><span class="mi">10</span><span class="p">]{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">};</span> <span class="o">&lt;&lt;</span> <span class="n">helper</span> <span class="n">array</span><span class="o">!</span> </span></span><span class="line"><span class="cl"> <span class="p">...</span> </span></span><span class="line"><span class="cl"> </span></span></code></pre></div><p>For instance, if you have 4MB of stack space and your default configuration is 1MB, you might occasionally encounter this bug depending on your call stack. This scenario can be quite tricky to catch!</p> <p>Fortunately, it&rsquo;s fixed in C++26:</p> <h2 id="step-4-the-c26-solution"> Step 4: The C++26 Solution <a class="hash-link" href="#step-4-the-c26-solution" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Thanks to &ldquo;Static storage for braced initializers <a href="https://wg21.link/P2752R3">P2752R3</a>&rdquo;, in C++26, similar to string literals, arrays for initializer list go into static storage!</p> <p>What&rsquo;s more, the fix can be implemented against C++11, so just by compiling with some of the latest compiler, your code might simply get safer.</p> <h2 id="conclusion"> Conclusion <a class="hash-link" href="#conclusion" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In this blog post, we went through a simple scenario where we wrote a buggy code, but thanks to C++26, the code will be safer. The first bug was easy to fix, but it can be missed as current compilers only report warnings. Thanks to C++26, you&rsquo;ll see a hard compiler error, so you have to address the issue of returning references to temporary objects. But with the fix, we introduced another potential issue with stack overflow. This one is tricky, and even expert coders might not be aware of this subtle issue. But again, thanks to C++26, the bug will disappear with the latest compiler versions.</p> <h4 id="back-to-you"> Back to you </h4> <p>• Have you encountered similar memory management challenges in your C++ projects?<br> • Are you planning to switch to newer C++ standards to leverage these safety features?</p> <p>Share your experiences and thoughts in the comments below!</p> 8 More C++23 Examples https://www.cppstories.com/2024/cpp23_more_examples/ Mon, 30 Dec 2024 00:00:00 +0000 https://www.cppstories.com/2024/cpp23_more_examples/ <p>In this article, you&rsquo;ll see eight larger examples that illustrate the changes in C++23.</p> <p>C++23 brings a ton of cool features, as you can see in my two previous articles (<a href="https://www.cppstories.com/2024/cpp23_lang/">here</a> and <a href="https://www.cppstories.com/2024/cpp23_lib/">here</a>). So far, we explored each new addition one by one, but I&rsquo;d like to share more examples that combine multiple features.</p> <p>Here we go:</p> <h2 id="1-stdrangesto"> 1. <code>std::ranges::to&lt;&gt;</code> <a class="hash-link" href="#1-stdrangesto" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The <code>ranges::to&lt;&gt;</code> feature allows you to convert ranges into containers easily:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unordered_map&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;map&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">numbers</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">unordered_map</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">number_to_text</span> <span class="o">=</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="s">&#34;one&#34;</span><span class="p">},</span> <span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="s">&#34;two&#34;</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="s">&#34;three&#34;</span><span class="p">},</span> <span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="s">&#34;four&#34;</span><span class="p">},</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="s">&#34;five&#34;</span><span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="mi">6</span><span class="p">,</span> <span class="s">&#34;six&#34;</span><span class="p">},</span> <span class="p">{</span><span class="mi">7</span><span class="p">,</span> <span class="s">&#34;seven&#34;</span><span class="p">},</span> <span class="p">{</span><span class="mi">8</span><span class="p">,</span> <span class="s">&#34;eight&#34;</span><span class="p">},</span> <span class="p">{</span><span class="mi">9</span><span class="p">,</span> <span class="s">&#34;nine&#34;</span><span class="p">},</span> <span class="p">{</span><span class="mi">10</span><span class="p">,</span> <span class="s">&#34;ten&#34;</span><span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">even_numbers</span> <span class="o">=</span> <span class="n">numbers</span> </span></span><span class="line"><span class="cl"> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">filter</span><span class="p">([](</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">n</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span> <span class="p">})</span> </span></span><span class="line"><span class="cl"> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">to</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&gt;</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">text_numbers_map</span> <span class="o">=</span> <span class="n">even_numbers</span> </span></span><span class="line"><span class="cl"> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">transform</span><span class="p">([</span><span class="o">&amp;</span><span class="n">number_to_text</span><span class="p">](</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">pair</span><span class="p">{</span><span class="n">n</span><span class="p">,</span> <span class="n">number_to_text</span><span class="p">.</span><span class="n">contains</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="o">?</span> </span></span><span class="line"><span class="cl"> <span class="n">number_to_text</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">:</span> <span class="s">&#34;unknown&#34;</span> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">})</span> </span></span><span class="line"><span class="cl"> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">to</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&gt;</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Even numbers: &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="nl">n</span> <span class="p">:</span> <span class="n">even_numbers</span><span class="p">)</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">n</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">Textual numbers:</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">]</span> <span class="o">:</span> <span class="n">text_numbers_map</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">k</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; -&gt; &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">v</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/jan3PG7GM">@Compiler Explorer</a></p> <p>As you can see, there&rsquo;s no issue in creating not only vectors but maps as well.</p> <h2 id="2-stdprint-and-stdprintln"> 2. <code>std::print</code> and <code>std::println</code> <a class="hash-link" href="#2-stdprint-and-stdprintln" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The new formatted output library simplifies printing. Here&rsquo;s an example that demonstrates alignment, formatting, and table creation:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unordered_map&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;numeric&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Store the data in an unordered_map (country -&gt; size in km²) </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">unordered_map</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="kt">double</span><span class="o">&gt;</span> <span class="n">country_sizes</span> <span class="o">=</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s">&#34;USA&#34;</span><span class="p">,</span> <span class="mi">9833517</span><span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s">&#34;Canada&#34;</span><span class="p">,</span> <span class="mi">9984670</span><span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s">&#34;Australia&#34;</span><span class="p">,</span> <span class="mi">7692024</span><span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s">&#34;China&#34;</span><span class="p">,</span> <span class="mi">9596961</span><span class="p">},</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s">&#34;Poland&#34;</span><span class="p">,</span> <span class="mi">312696</span><span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">constexpr</span> <span class="kt">double</span> <span class="n">KM_TO_MI</span> <span class="o">=</span> <span class="mf">0.386102</span><span class="p">;</span> <span class="c1">// Conversion factor </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">double</span> <span class="n">total_km</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">accumulate</span><span class="p">(</span><span class="n">country_sizes</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">country_sizes</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="mf">0.0</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="p">[](</span><span class="kt">double</span> <span class="n">sum</span><span class="p">,</span> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">entry</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">sum</span> <span class="o">+</span> <span class="n">entry</span><span class="p">.</span><span class="n">second</span><span class="p">;</span> <span class="p">});</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">double</span> <span class="n">total_mi</span> <span class="o">=</span> <span class="n">total_km</span> <span class="o">*</span> <span class="n">KM_TO_MI</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Table headers </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{:&lt;15} | {:&gt;15} | {:&gt;15}&#34;</span><span class="p">,</span> <span class="s">&#34;Country&#34;</span><span class="p">,</span> <span class="s">&#34;Size (km²)&#34;</span><span class="p">,</span> <span class="s">&#34;Size (mi²)&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{:-&lt;15}-+-{:-&lt;15}-+-{:-&lt;15}&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">);</span> <span class="c1">// Separator line </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"> <span class="c1">// Table rows </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[</span><span class="n">country</span><span class="p">,</span> <span class="n">size_km</span><span class="p">]</span> <span class="o">:</span> <span class="n">country_sizes</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">double</span> <span class="n">size_mi</span> <span class="o">=</span> <span class="n">size_km</span> <span class="o">*</span> <span class="n">KM_TO_MI</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{:&lt;15} | {:&gt;15.0f} | {:&gt;15.2f}&#34;</span><span class="p">,</span> <span class="n">country</span><span class="p">,</span> <span class="n">size_km</span><span class="p">,</span> <span class="n">size_mi</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Footer </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{:-&lt;15}-+-{:-&lt;15}-+-{:-&lt;15}&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">);</span> <span class="c1">// Separator line </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{:&lt;15} | {:&gt;15.0f} | {:&gt;15.2f}&#34;</span><span class="p">,</span> <span class="s">&#34;Total&#34;</span><span class="p">,</span> <span class="n">total_km</span><span class="p">,</span> <span class="n">total_mi</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/87T1M64se">@Compiler Explorer</a></p> <p>Example output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Country | Size (km²) | Size (mi²) </span></span><span class="line"><span class="cl">----------------+-----------------+---------------- </span></span><span class="line"><span class="cl">Poland | 312696 | 120732.55 </span></span><span class="line"><span class="cl">China | 9596961 | 3705405.84 </span></span><span class="line"><span class="cl">Australia | 7692024 | 2969905.85 </span></span><span class="line"><span class="cl">Canada | 9984670 | 3855101.06 </span></span><span class="line"><span class="cl">USA | 9833517 | 3796740.58 </span></span><span class="line"><span class="cl">----------------+-----------------+---------------- </span></span><span class="line"><span class="cl">Total | 37419868 | 14447885.87 </span></span></code></pre></div><h2 id="3-stdoptional-monadic-operations"> 3. <code>std::optional</code> Monadic Operations <a class="hash-link" href="#3-stdoptional-monadic-operations" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The new <code>and_then</code>, <code>transform</code>, and <code>or_else</code> functions make working with <code>std::optional</code> more expressive. Here&rsquo;s an example of chain operations that process user input.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;optional&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">get_user_input</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">input</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Enter your name: &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">getline</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">cin</span><span class="p">,</span> <span class="n">input</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">nullopt</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">input</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">result</span> <span class="o">=</span> <span class="n">get_user_input</span><span class="p">()</span> </span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">transform</span><span class="p">([](</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">transform</span><span class="p">(</span><span class="n">name</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">name</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">name</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="o">::</span><span class="n">toupper</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">name</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">})</span> </span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">and_then</span><span class="p">([](</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">name</span> <span class="o">==</span> <span class="s">&#34;ADMIN&#34;</span><span class="p">)</span> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="p">(</span><span class="s">&#34;Welcome, Admin!&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="p">(</span><span class="s">&#34;Hello, &#34;</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="s">&#34;!&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">})</span> </span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">or_else</span><span class="p">([]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="p">(</span><span class="s">&#34;No input provided.&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="o">*</span><span class="n">result</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Experiment at <a href="https://godbolt.org/z/9vose5j1f">@Compiler Explorer</a></p> <h2 id="4-stdgenerator"> 4. <code>std::generator</code> <a class="hash-link" href="#4-stdgenerator" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The <code>std::generator</code> feature simplifies creating lazy sequences. Here&rsquo;s an example of reading line by line from a file:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">to_uppercase</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">str</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">transform</span><span class="p">(</span><span class="n">str</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">str</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">str</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="o">::</span><span class="n">toupper</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">str</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">ProcessedLine</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">original</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">uppercase</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">generator</span><span class="o">&lt;</span><span class="n">ProcessedLine</span><span class="o">&gt;</span> <span class="n">read_and_process_lines</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">filename</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ifstream</span> <span class="n">file</span><span class="p">(</span><span class="n">filename</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">line</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">getline</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="n">line</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">ProcessedLine</span> <span class="n">processed</span><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">line</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">to_uppercase</span><span class="p">(</span><span class="n">line</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">co_yield</span> <span class="n">processed</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">temp_filename</span> <span class="o">=</span> <span class="s">&#34;temp_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span> <span class="n">temp_file</span><span class="p">(</span><span class="n">temp_filename</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">temp_file</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Line 1: Hello, World!</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">temp_file</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Line 2: This is a test.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">temp_file</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Line 3: C++ coroutines are cool!</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">processed</span> <span class="p">:</span> <span class="n">read_and_process_lines</span><span class="p">(</span><span class="n">temp_filename</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Original : &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">processed</span><span class="p">.</span><span class="n">original</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Uppercase: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">processed</span><span class="p">.</span><span class="n">uppercase</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/qTzTcP9Kb">@Compiler Explorer</a></p> <h2 id="5-stdmdspan"> 5. <code>std::mdspan</code> <a class="hash-link" href="#5-stdmdspan" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The <code>std::mdspan</code> feature is useful for multidimensional data. Here&rsquo;s an example of matrix multiplication.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;https://raw.githubusercontent.com/kokkos/mdspan/single-header/mdspan.hpp&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">multiply_matrices</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">A</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">B</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">C</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">A</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">B</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{}{}: &#34;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">k</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="n">A</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="o">++</span><span class="n">k</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;+= {} x {}, &#34;</span><span class="p">,</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">k</span><span class="p">],</span> <span class="n">B</span><span class="p">[</span><span class="n">k</span><span class="p">,</span> <span class="n">j</span><span class="p">]);</span> </span></span><span class="line"><span class="cl"> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span> <span class="o">+=</span> <span class="n">A</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">k</span><span class="p">]</span> <span class="o">*</span> <span class="n">B</span><span class="p">[</span><span class="n">k</span><span class="p">,</span> <span class="n">j</span><span class="p">];</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">A_data</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">B_data</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">C_data</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">A</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="p">(</span><span class="n">A_data</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">B</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="p">(</span><span class="n">B_data</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">C</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="p">(</span><span class="n">C_data</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">multiply_matrices</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">C</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">C</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} &#34;</span><span class="p">,</span> <span class="n">C</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Experiment <a href="https://godbolt.org/z/9xb8da8jo">@Compiler Explorer</a></p> <h2 id="6-cartesian_product-enumerate-and-zip"> 6. <code>cartesian_product</code>, <code>enumerate</code>, and <code>zip</code> <a class="hash-link" href="#6-cartesian_product-enumerate-and-zip" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">range1</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">range2</span> <span class="o">=</span> <span class="p">{</span><span class="sc">&#39;A&#39;</span><span class="p">,</span> <span class="sc">&#39;B&#39;</span><span class="p">,</span> <span class="sc">&#39;C&#39;</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">product</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">cartesian_product</span><span class="p">(</span><span class="n">range1</span><span class="p">,</span> <span class="n">range2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Cartesian Product:&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">]</span> <span class="o">:</span> <span class="n">product</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;({}, {})&#34;</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">enumerated</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">enumerate</span><span class="p">(</span><span class="n">range1</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;</span><span class="se">\n</span><span class="s">Enumerated Range:&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[</span><span class="n">index</span><span class="p">,</span> <span class="n">value</span><span class="p">]</span> <span class="o">:</span> <span class="n">enumerated</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Index: {}, Value: {}&#34;</span><span class="p">,</span> <span class="n">index</span><span class="p">,</span> <span class="n">value</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">zipped</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">zip</span><span class="p">(</span><span class="n">range1</span><span class="p">,</span> <span class="n">range2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;</span><span class="se">\n</span><span class="s">Zipped Ranges:&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">]</span> <span class="o">:</span> <span class="n">zipped</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;({}, {})&#34;</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/j6TjjjEaP">@Compiler Explorer</a></p> <h2 id="7-chunk-slide-and-stride"> 7. <code>chunk</code>, <code>slide</code> and <code>stride</code> <a class="hash-link" href="#7-chunk-slide-and-stride" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">numbers</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Chunk: divide the range into groups of 3 </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">chunks</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">chunk</span><span class="p">(</span><span class="n">numbers</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Chunks of 3:&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">chunk</span> <span class="p">:</span> <span class="n">chunks</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="nl">n</span> <span class="p">:</span> <span class="n">chunk</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} &#34;</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Slide: create overlapping subranges of size 3 </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">sliding</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">slide</span><span class="p">(</span><span class="n">numbers</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;</span><span class="se">\n</span><span class="s">Sliding Window of 3:&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">window</span> <span class="p">:</span> <span class="n">sliding</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="nl">n</span> <span class="p">:</span> <span class="n">window</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} &#34;</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Stride: skip every 2 elements </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">strided</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">stride</span><span class="p">(</span><span class="n">numbers</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;</span><span class="se">\n</span><span class="s">Strided Range (step 2):&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="nl">n</span> <span class="p">:</span> <span class="n">strided</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{} &#34;</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/Yb5WzE6nx">@Compiler Explorer</a></p> <h2 id="8-chunk-enumerate-and-fold_left"> 8. <code>chunk</code>, <code>enumerate</code> and <code>fold_left</code> <a class="hash-link" href="#8-chunk-enumerate-and-fold_left" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Here&rsquo;s an example where we process simple strings into words and sentences and provide simple stats:</p> <p>Core part:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">split_into_words</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">text</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">text</span> </span></span><span class="line"><span class="cl"> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">split</span><span class="p">(</span><span class="sc">&#39; &#39;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">transform</span><span class="p">([](</span><span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">word_range</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">(</span><span class="n">word_range</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">word_range</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">})</span> </span></span><span class="line"><span class="cl"> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">to</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&gt;</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">analyze_sentence</span><span class="p">(</span><span class="n">size_t</span> <span class="n">index</span><span class="p">,</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;&amp;</span> <span class="n">words</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">size_t</span> <span class="n">word_count</span> <span class="o">=</span> <span class="n">words</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">double</span> <span class="n">total_word_length</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">fold_left</span><span class="p">(</span><span class="n">words</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="p">[](</span><span class="kt">double</span> <span class="n">sum</span><span class="p">,</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">word</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">sum</span> <span class="o">+</span> <span class="n">word</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">double</span> <span class="n">avg_word_length</span> </span></span><span class="line"><span class="cl"> <span class="o">=</span> <span class="n">word_count</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">total_word_length</span> <span class="o">/</span> <span class="nl">word_count</span> <span class="p">:</span> <span class="mf">0.0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">longest_word</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">max</span><span class="p">(</span><span class="n">words</span><span class="p">,</span> <span class="p">{},</span> <span class="o">&amp;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">::</span><span class="n">size</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Sentence &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">index</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;: &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">w</span> <span class="p">:</span> <span class="n">words</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">w</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39; &#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s"> Word count: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">word_count</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; Average word length: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">avg_word_length</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; Longest word: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">longest_word</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">text</span> <span class="o">=</span> <span class="s">&#34;This is the first sentence. Here is another one! &#34;</span> </span></span><span class="line"><span class="cl"> <span class="s">&#34;And yet another sentence. It is fun to analyze text.&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">all_words</span> <span class="o">=</span> <span class="n">split_into_words</span><span class="p">(</span><span class="n">text</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">sentences</span> <span class="o">=</span> <span class="n">all_words</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">chunk_by</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="p">[](</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">a</span><span class="p">,</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="o">!</span><span class="n">a</span><span class="p">.</span><span class="n">ends_with</span><span class="p">(</span><span class="sc">&#39;.&#39;</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">a</span><span class="p">.</span><span class="n">ends_with</span><span class="p">(</span><span class="sc">&#39;!&#39;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[</span><span class="n">index</span><span class="p">,</span> <span class="n">sentence</span><span class="p">]</span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">enumerate</span><span class="p">(</span><span class="n">sentences</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">words</span> <span class="o">=</span> <span class="n">sentence</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">to</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&gt;</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">words</span><span class="p">.</span><span class="n">empty</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">words</span><span class="p">.</span><span class="n">back</span><span class="p">().</span><span class="n">ends_with</span><span class="p">(</span><span class="sc">&#39;.&#39;</span><span class="p">)</span> <span class="o">||</span> <span class="n">words</span><span class="p">.</span><span class="n">back</span><span class="p">().</span><span class="n">ends_with</span><span class="p">(</span><span class="sc">&#39;!&#39;</span><span class="p">)))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">words</span><span class="p">.</span><span class="n">back</span><span class="p">().</span><span class="n">pop_back</span><span class="p">();</span> <span class="c1">// Remove the sentence-ending punctuation for analysis </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="n">analyze_sentence</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="n">words</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/dsYevvxKs">@Compiler Explorer</a></p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Do you have some other cool examples with C++23 features?</li> <li>Have you played with C++23 library features?</li> <li>What are the most important features for you in this release?</li> </ul> <p>Share your comments below</p> C++23 Library Features and Reference Cards https://www.cppstories.com/2024/cpp23_lib/ Sun, 08 Dec 2024 00:00:00 +0000 https://www.cppstories.com/2024/cpp23_lib/ <p>In this blog post, you&rsquo;ll see all C++23 library features! Each with a short description and additional code example.</p> <p>Prepare for a ride!</p> <blockquote class="hint note"> For language features please see the previous article: <a href="https://www.cppstories.com/2024/cpp23_lang/">C++23 Language Features and Reference Cards - C++ Stories</a> </blockquote> <h2 id="want-your-own-copy-to-print"> Want your own copy to print? <a class="hash-link" href="#want-your-own-copy-to-print" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>If you like, I prepared PDF I packed both language and the Standard Library features. Each one has a short description and an example if possible.</p> <p><img src="../../images/2017cards.PNG" alt=""></p> <p>All of the existing subscribers of my mailing list have already got the new document, so If you want to download it just subscribe here:</p> <div style="width:80%;background-color:#fafafa;border-top:solid 1px #ef8f00;border-bottom:solid 1px #ef8f00;margin-left:auto;margin-right:auto;"> <div style="text-align:center;margin:1em 0 1em 0;"> <a style="color: #ffffff; text-decoration: none; font-family: Helvetica, Arial, sans-serif; font-weight: bold; font-size: 16px; line-height: 20px; padding: 10px; display: inline-block; max-width: 500px; text-shadow: rgba(0, 0, 0, 0.247059) 0px -1px 1px; box-shadow: rgba(255, 255, 255, 0.498039) 0px 1px 3px inset, rgba(0, 0, 0, 0.498039) 0px 1px 3px; background: #ef8f00;" href="http://eepurl.com/cyycFz" target="_blank">Download a free copy of C++23 Ref Card!</a> </div> </div> <p>Please notice that along with the new ref card you&rsquo;ll also get C++20 and C++17 language reference card that I initially published three years ago. With this &ldquo;package&rdquo; you&rsquo;ll quickly learn about all of the latest parts that Modern C++ acquired over the last few years.</p> <h2 id="new-headers"> New Headers <a class="hash-link" href="#new-headers" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li><code>expected</code></li> <li><code>flat_map</code>, <code>flat_set</code></li> <li><code>generator</code></li> <li><code>mdspan</code></li> <li><code>print</code></li> <li><code>spanstream</code></li> <li><code>stacktrace</code></li> <li><code>stdfloat</code></li> </ul> <h2 id="stacktrace-library"> Stacktrace Library <a class="hash-link" href="#stacktrace-library" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P0881">P0881</a></p> <p>Based on Boost.Stacktrace allows for more context when debugging code. The library defines components to store the stacktrace of the current thread of execution and query information about the stored stacktrace at runtime.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stacktrace&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">foo</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">stacktrace</span><span class="o">::</span><span class="n">current</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">[]</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">foo</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Experiment <a href="https://godbolt.org/z/ahTbsvb4h">@Compiler Explorer</a>, note that GCC 14 requires to be linked with <code>-lstdc++exp</code>.</p> <p>Possible output on GCC:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl"> 0# foo() at /app/example.cpp:5 </span></span><span class="line"><span class="cl"> 1# operator() at /app/example.cpp:10 </span></span><span class="line"><span class="cl"> 2# main at /app/example.cpp:11 </span></span><span class="line"><span class="cl"> 3# at :0 </span></span><span class="line"><span class="cl"> 4# __libc_start_main at :0 </span></span><span class="line"><span class="cl"> 5# _start at :0 </span></span></code></pre></div><h2 id="is_scoped_enum--to_underlying"> <code>is_scoped_enum</code> &amp; <code>to_underlying</code> <a class="hash-link" href="#is_scoped_enum--to_underlying" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P1048R1">P1048R1</a> (<code>is_scoped_enum</code>), <a href="https://wg21.link/P1682R3">P1682R3</a> (<code>to_underlying</code>)</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;utility&gt; // for std::to_underlying</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="k">class</span> <span class="nc">Color</span><span class="o">:</span> <span class="kt">uint8_t</span> <span class="p">{</span> <span class="n">Red</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">Green</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span> <span class="n">Blue</span> <span class="o">=</span> <span class="mi">3</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="nc">Col</span> <span class="p">{</span> <span class="n">Red</span><span class="p">,</span> <span class="n">Green</span><span class="p">,</span> <span class="n">Blue</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Color</span> <span class="n">c</span> <span class="o">=</span> <span class="n">Color</span><span class="o">::</span><span class="n">Blue</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Pre-C++23: verbose casting </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">old_way</span> <span class="o">=</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">underlying_type_t</span><span class="o">&lt;</span><span class="n">Color</span><span class="o">&gt;&gt;</span><span class="p">(</span><span class="n">c</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// C++23: clean and simple </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">new_way</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">to_underlying</span><span class="p">(</span><span class="n">c</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Color value: {}&#34;</span><span class="p">,</span> <span class="n">new_way</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;is_scoped_enum Color {}&#34;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">is_scoped_enum_v</span><span class="o">&lt;</span><span class="n">Color</span><span class="o">&gt;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;is_scoped_enum Col {}&#34;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">is_scoped_enum_v</span><span class="o">&lt;</span><span class="n">Col</span><span class="o">&gt;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/h8hd7Y8oY">@Compiler Explorer</a></p> <p>The trait (<code>underlying_type</code>) has been available since C++11.</p> <p>Bonus: First notes and ideas about <code>to_underlying</code> appeared in Scott Meyers&rsquo; book: <a href="https://amzn.to/3t5tmS4">Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14</a> @Amazon.</p> <h2 id="stdstringstdstring_view-improvements"> <code>std::string</code>/<code>std::string_view</code> Improvements <a class="hash-link" href="#stdstringstdstring_view-improvements" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li><code>contains(char/string_view/const char*)</code> - member function</li> <li>Prohibiting <code>std::basic_string</code> and <code>std::basic_string_view</code> construction from <code>nullptr</code></li> <li>Range constructor for <code>std::basic_string_view</code> - <a href="https://wg21.link/P1989R2">P1989</a></li> <li><code>string::resize_and_overwrite()</code> - <a href="https://wg21.link/P1072R10">P1072R10</a> - Allows us to initialize/resize strings without clearing the buffer but filling bytes with some user operation.</li> </ul> <p>See the example below:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string_view&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// 1. contains() example </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">str</span> <span class="o">=</span> <span class="s">&#34;Hello C++23 World&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{}&#34;</span><span class="p">,</span> <span class="n">str</span><span class="p">.</span><span class="n">contains</span><span class="p">(</span><span class="s">&#34;C++23&#34;</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{}&#34;</span><span class="p">,</span> <span class="n">str</span><span class="p">.</span><span class="n">contains</span><span class="p">(</span><span class="sc">&#39;X&#39;</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// 2. resize_and_overwrite() example </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">numbers</span> <span class="p">{</span><span class="s">&#34;xyz&#34;</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">numbers</span><span class="p">.</span><span class="n">resize_and_overwrite</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="p">[](</span><span class="kt">char</span><span class="o">*</span> <span class="n">buf</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">size_t</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">buf</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;0&#39;</span> <span class="o">+</span> <span class="n">i</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">n</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Numbers: {}&#34;</span><span class="p">,</span> <span class="n">numbers</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// 3. string_view range constructor </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">chars</span> <span class="o">=</span> <span class="p">{</span><span class="sc">&#39;H&#39;</span><span class="p">,</span> <span class="sc">&#39;e&#39;</span><span class="p">,</span> <span class="sc">&#39;l&#39;</span><span class="p">,</span> <span class="sc">&#39;l&#39;</span><span class="p">,</span> <span class="sc">&#39;o&#39;</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">sv</span><span class="p">(</span><span class="n">chars</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">chars</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;View: {}&#34;</span><span class="p">,</span> <span class="n">sv</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/xTsba48hb">@Compiler Explorer</a></p> <h2 id="stdout_ptr-stdinout_ptr"> <code>std::out_ptr()</code>, <code>std::inout_ptr()</code>, <a class="hash-link" href="#stdout_ptr-stdinout_ptr" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https:/wg21.link/P1132">P1132</a></p> <p>Functions that wrap a smart pointer into a special type allowing to pass to low-level functions that require pointer-to-pointer parameters.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">lowLevel</span><span class="p">(</span><span class="kt">int</span><span class="o">**</span> <span class="n">pp</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">pp</span><span class="p">)</span> <span class="o">*</span><span class="n">pp</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="p">{</span><span class="mi">42</span><span class="p">};</span> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">ptr</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">lowLevel</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">inout_ptr</span><span class="p">(</span><span class="n">ptr</span><span class="p">));</span> </span></span></code></pre></div><p>Handy for interaction with C-style API like WindowsAPI, DirectX, Media libraries. <code>inout_ptr</code> additionally calls <code>.release()</code> on the pointer.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;memory&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;utility&gt; // for out_ptr/inout_ptr</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="c1">// Simulate C-style API functions </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">void</span> <span class="nf">AllocateResource</span><span class="p">(</span><span class="kt">int</span><span class="o">**</span> <span class="n">pp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="o">*</span><span class="n">pp</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="p">{</span><span class="mi">42</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">ModifyResource</span><span class="p">(</span><span class="kt">int</span><span class="o">**</span> <span class="n">pp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">pp</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="o">**</span><span class="n">pp</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">CleanupResource</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span> <span class="n">p</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">delete</span> <span class="n">p</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Example 1: out_ptr for new allocation </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="k">decltype</span><span class="p">(</span><span class="o">&amp;</span><span class="n">CleanupResource</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">resource1</span><span class="p">(</span><span class="k">nullptr</span><span class="p">,</span> <span class="n">CleanupResource</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">AllocateResource</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">out_ptr</span><span class="p">(</span><span class="n">resource1</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Resource1 value: {}&#34;</span><span class="p">,</span> <span class="o">*</span><span class="n">resource1</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Example 2: inout_ptr for modifying existing resource </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">resource2</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Resource2 before: {}&#34;</span><span class="p">,</span> <span class="o">*</span><span class="n">resource2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">ModifyResource</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">inout_ptr</span><span class="p">(</span><span class="n">resource2</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Resource2 after: {}&#34;</span><span class="p">,</span> <span class="o">*</span><span class="n">resource2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Play <a href="https://godbolt.org/z/fWsK9soMb">@Compiler Explorer</a></p> <p>See another example: <a href="https://godbolt.org/z/KerKM7fM8">https://godbolt.org/z/KerKM7fM8</a></p> <h2 id="rangesto"> <code>ranges::to&lt;&gt;</code> <a class="hash-link" href="#rangesto" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P1206">P1206</a></p> <p>A way to build containers from a view:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">v</span> <span class="o">=</span> <span class="n">iota</span><span class="p">(</span><span class="sc">&#39;a&#39;</span><span class="p">)</span> <span class="o">|</span> <span class="n">take</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">vec</span> <span class="o">=</span> <span class="n">v</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">to</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&gt;</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">str</span> <span class="o">=</span> <span class="n">v</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">to</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="p">();</span> </span></span></code></pre></div><p>When a container has a <code>reserve()</code> function, <code>ranges:to</code> will also try to use it to make creation more optimal.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;concepts&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> </span></span><span class="line"><span class="cl"><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">v</span> <span class="o">=</span> <span class="n">iota</span><span class="p">(</span><span class="sc">&#39;a&#39;</span><span class="p">)</span> <span class="o">|</span> <span class="n">take</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="c1">// new in C++23 </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">vec</span> <span class="o">=</span> <span class="n">v</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">to</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&gt;</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">x</span> <span class="p">:</span> <span class="n">vec</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">x</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">vec2</span> <span class="o">=</span> <span class="n">vec</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">views</span><span class="o">::</span><span class="n">reverse</span> <span class="o">|</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">to</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&gt;</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">x</span> <span class="p">:</span> <span class="n">vec2</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">x</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/5sE3z9hWd">@Compiler Explorer</a></p> <h2 id="ranges-algorithms"> Ranges Algorithms <a class="hash-link" href="#ranges-algorithms" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li><code>ranges::starts_with()</code> and <code>ranges::ends_with()</code></li> <li><code>ranges::iota()</code>, <code>ranges::shift_left/right()</code></li> <li><code>ranges::find_last()</code>, <code>find_last_if()</code>, <code>find_last_if_not()</code></li> <li><code>ranges::contains()</code> and <code>ranges::contains_subrange()</code></li> <li>Ranges fold algorithms: <code>ranges::fold_*()</code></li> </ul> <p>See a simple example with <code>fold_left</code> and <code>contains</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;numeric&gt; // For std::accumulate (used for comparison)</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;algorithm&gt; // new fold_left, ends_with</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">numbers</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">sum</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">fold_left</span><span class="p">(</span><span class="n">numbers</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[](</span><span class="kt">int</span> <span class="n">acc</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">acc</span> <span class="o">+</span> <span class="n">n</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Sum of numbers: {}&#34;</span><span class="p">,</span> <span class="n">sum</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">std_sum</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">accumulate</span><span class="p">(</span><span class="n">numbers</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">numbers</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="mi">0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Sum using std::accumulate: {}&#34;</span><span class="p">,</span> <span class="n">std_sum</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">bool</span> <span class="n">contains_four</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">contains</span><span class="p">(</span><span class="n">numbers</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Does the range contains 4? {}&#34;</span><span class="p">,</span> <span class="n">contains_four</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/8We8zKeaz">@Compiler Explorer</a></p> <h2 id="views-additions"> Views Additions <a class="hash-link" href="#views-additions" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li><code>cartesian_product</code></li> <li><code>repeat</code></li> <li><code>enumerate</code></li> <li><code>adjacent</code>, <code>adjacent_transform</code></li> <li><code>stride</code></li> <li><code>slide</code></li> <li><code>chunk</code>, <code>chunk_by</code></li> <li><code>join_with</code></li> <li><code>zip</code>, <code>zip_transform</code></li> <li><code>as_rvalue</code>, <code>as_const</code></li> </ul> <p>For <code>zip</code> you can see my other article: <a href="https://www.cppstories.com/2023/view-zip/">Combining Collections with Zip in C++23 for Efficient Data Processing - C++ Stories</a>.</p> <p>And for more examples see my free article @Patreon: <a href="https://www.patreon.com/posts/seven-more-c-23-117979481">Seven more C++23 Library Examples | Patreon</a>.</p> <h2 id="heterogeneous-erasure-for-associative-containers"> Heterogeneous Erasure for Associative Containers <a class="hash-link" href="#heterogeneous-erasure-for-associative-containers" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2077">P2077</a></p> <p>Continuation of the work for heterogeneous operations. This time you can use transparent comparators for <code>erase()</code> and <code>extract()</code> member functions. To be backward compatible, the comparators cannot be convertible to <code>iterator</code> or <code>const_iterator</code> of a given container.</p> <p>Read more about heterogeneous access in my other article: <a href="https://www.cppstories.com/2021/heterogeneous-access-cpp20/">C++20: Heterogeneous Lookup in (Un)ordered Containers - C++ Stories</a></p> <h2 id="monadic-operations-for-stdoptional"> Monadic Operations for <code>std::optional</code> <a class="hash-link" href="#monadic-operations-for-stdoptional" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P0798">P0798</a></p> <p>New member functions for optional: <code>and_then</code>, <code>transform</code>, and <code>or_else</code>.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">userName</span><span class="p">.</span><span class="n">transform</span><span class="p">(</span><span class="n">toUpper</span><span class="p">)</span> </span></span><span class="line"><span class="cl"><span class="p">.</span><span class="n">and_then</span><span class="p">([](</span><span class="n">string</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nf">make_optional</span><span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="s">&#34;OK&#34;</span><span class="p">);</span> <span class="p">})</span> </span></span><span class="line"><span class="cl"><span class="p">.</span><span class="n">or_else</span><span class="p">([]</span> <span class="p">{</span> <span class="k">return</span> <span class="nf">make_optional</span><span class="p">(</span><span class="n">string</span><span class="p">{</span><span class="s">&#34;no user&#34;</span><span class="p">});</span> <span class="p">});</span> </span></span></code></pre></div><p>For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;optional&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">test</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;&amp;</span> <span class="n">userName</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">up</span> <span class="o">=</span> <span class="p">[](</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">transform</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="o">::</span><span class="n">toupper</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">x</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">userName</span><span class="p">.</span><span class="n">transform</span><span class="p">(</span><span class="n">up</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">and_then</span><span class="p">([](</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;x: {}&#34;</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">size</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">})</span> </span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">or_else</span><span class="p">([]{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;empty...&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="p">});</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;ret is {}&#34;</span><span class="p">,</span> <span class="o">*</span><span class="n">ret</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">test</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">nullopt</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">test</span><span class="p">(</span><span class="s">&#34;john&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/h151z8EPn">@Compiler Explorer</a></p> <p>output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">empty... </span></span><span class="line"><span class="cl">ret is 0 </span></span><span class="line"><span class="cl">x: JOHN </span></span><span class="line"><span class="cl">ret is 4 </span></span></code></pre></div><p>See my full article about this extension here: <a href="https://www.cppstories.com/2023/monadic-optional-ops-cpp23/">How to Use Monadic Operations for `std::optional` in C++23 - C++ Stories</a></p> <h2 id="expected-and-its-monadic-operations"> <code>&lt;expected&gt;</code> and Its Monadic Operations <a class="hash-link" href="#expected-and-its-monadic-operations" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P0323">P0323</a></p> <p>A vocabulary type that allows storing either of two values: <code>T</code> or <code>unexpected</code> (in a form of some error type). It’s something between <code>std::optional</code> and <code>std::variant</code>.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">enum</span> <span class="k">class</span> <span class="nc">FuelErr</span> <span class="p">{</span> <span class="n">DistLarge</span><span class="p">,</span> <span class="n">Neg</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">expected</span><span class="o">&lt;</span><span class="kt">double</span><span class="p">,</span> <span class="n">FuelErr</span><span class="o">&gt;</span> <span class="n">calcFuel</span><span class="p">(</span><span class="kt">int</span> <span class="n">dst</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">dst</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">unexpected</span><span class="p">(</span><span class="n">FuelErr</span><span class="o">::</span><span class="n">Neg</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">distance</span> <span class="o">*</span> <span class="mf">1.333</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>C++23 also adds monadic operations for this type, so it’s consistent with operations for <code>std::optional</code>.</p> <p>See my mini-series about this type:</p> <ul> <li><a href="https://www.cppstories.com/2024/expected-cpp23/">Using std::expected from C++23 - C++ Stories</a></li> <li><a href="https://www.cppstories.com/2024/expected-cpp23-internals/">Understand internals of std::expected - C++ Stories</a></li> <li><a href="https://www.cppstories.com/2024/expected-cpp23-monadic/">std::expected - Monadic Extensions - C++ Stories</a></li> <li><a href="https://www.cppstories.com/2024/pipe-operator/">Function Composition and the Pipe Operator in C++23 – With std::expected - C++ Stories</a> (guest post)</li> </ul> <h2 id="constexpr-stdunique_ptr"> <code>constexpr std::unique_ptr</code> <a class="hash-link" href="#constexpr-stdunique_ptr" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2273">P2273</a></p> <p>The <code>new()</code> operator can be used in <code>constexpr</code> context since C++20, and now you can wrap it also in a <code>unique_ptr</code>.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;numeric&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;memory&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="kt">int</span> <span class="nf">naiveSum</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">p</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">[]</span><span class="o">&gt;</span><span class="p">(</span><span class="n">n</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">iota</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">get</span><span class="p">(),</span> <span class="n">p</span><span class="p">.</span><span class="n">get</span><span class="p">()</span><span class="o">+</span><span class="n">n</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">accumulate</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">get</span><span class="p">(),</span> <span class="n">p</span><span class="p">.</span><span class="n">get</span><span class="p">()</span><span class="o">+</span><span class="n">n</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">tmp</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="kt">int</span> <span class="nf">smartSum</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">(</span><span class="n">n</span><span class="o">*</span><span class="p">(</span><span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">naiveSum</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="o">==</span> <span class="n">smartSum</span><span class="p">(</span><span class="mi">10</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">naiveSum</span><span class="p">(</span><span class="mi">11</span><span class="p">)</span> <span class="o">==</span> <span class="n">smartSum</span><span class="p">(</span><span class="mi">11</span><span class="p">));</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/K6sq3hn4b">@Compiler Explorer</a></p> <h2 id="stdmdspan-multidimensional-span-p0009"> <code>std::mdspan</code> Multidimensional Span, P0009 <a class="hash-link" href="#stdmdspan-multidimensional-span-p0009" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>A generalization over <code>std::span</code> for multiple dimensions. Supports dynamic as well as static extents (compile-time constants). It also supports various mappings like column-major order, row-major, or even stride access.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;https://raw.githubusercontent.com/kokkos/mdspan/single-header/mdspan.hpp&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">isSymmetric</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">dextents</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="mi">2</span><span class="o">&gt;&gt;</span> <span class="n">matrix</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">rows</span> <span class="o">=</span> <span class="n">matrix</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">cols</span> <span class="o">=</span> <span class="n">matrix</span><span class="p">.</span><span class="n">extent</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">rows</span> <span class="o">!=</span> <span class="n">cols</span><span class="p">)</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0u</span><span class="n">z</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">rows</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">j</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">cols</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">matrix</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span> <span class="o">!=</span> <span class="n">matrix</span><span class="p">[</span><span class="n">j</span><span class="p">,</span> <span class="n">i</span><span class="p">])</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">matrix_data</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">matrix</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="p">(</span><span class="n">matrix_data</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">isSymmetric</span><span class="p">(</span><span class="n">matrix</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See at <a href="https://godbolt.org/z/aYs7v883h">Compiler Explorer</a></p> <p>And see my two bonus articles, available for Patreons, about this type:</p> <ul> <li><a href="https://www.patreon.com/posts/std-mdspan-from-91364126"><code>std::mdspan</code> in C++23</a></li> <li><a href="https://www.patreon.com/posts/std-mdspan-from-92660644"><code>std::mdspan</code> in C++23 - 2 - ops and customization</a></li> <li><a href="https://www.patreon.com/posts/std-mdspan-from-93441144"><code>std::mdspan</code> in C++23 - 3 - Dynamic Programming</a></li> </ul> <h2 id="flat_map-and-flat_set"> <code>&lt;flat_map&gt;</code> and <code>&lt;flat_set&gt;</code> <a class="hash-link" href="#flat_map-and-flat_set" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P0429">P0429</a> and <a href="https://wg21.link/P1222">P1222</a></p> <p>Drop-in replacement for maps and sets with better performance characteristics. It gives faster lookup, faster iteration, random access iteration, less memory, and better cache efficiency. But iterators might be invalidated, and insertion is slower than the tree approach. The container is actually a container adaptor with proxy iterators.</p> <p>Here&rsquo;s a reference implementation: <a href="https://github.com/tzlaine/flat_map/blob/master/implementation/flat_map">https://github.com/tzlaine/flat_map/blob/master/implementation/flat_map</a></p> <h2 id="formatted-output-library-print"> Formatted Output Library <code>&lt;print&gt;</code> <a class="hash-link" href="#formatted-output-library-print" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2093">P2093</a></p> <p>New Hello World Style for C++23!</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt; </span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt; </span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span> <span class="o">=</span> <span class="s">&#34;C++23&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">year</span> <span class="o">=</span> <span class="mi">2024</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="kt">double</span> <span class="n">version</span> <span class="o">=</span> <span class="mf">23.0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Basic printing </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Hello from {}!&#34;</span><span class="p">,</span> <span class="n">name</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Named arguments </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Language: {0}, Version: {0}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">name</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Multiple arguments with formatting </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Release year: {:d}, Version: {:.1f}&#34;</span><span class="p">,</span> <span class="n">year</span><span class="p">,</span> <span class="n">version</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Alignment and width </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{:&gt;10}: {:&gt;5}&#34;</span><span class="p">,</span> <span class="s">&#34;Status&#34;</span><span class="p">,</span> <span class="s">&#34;OK&#34;</span><span class="p">);</span> <span class="c1">// right-aligned </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;{:&lt;10}: {:&lt;5}&#34;</span><span class="p">,</span> <span class="s">&#34;Error&#34;</span><span class="p">,</span> <span class="s">&#34;None&#34;</span><span class="p">);</span> <span class="c1">// left-aligned </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"> <span class="c1">// Print without newline and then with newline </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Loading&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;... done!&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/ceWha1zcr">@Compiler Explorer</a></p> <p>New functions in the <code>&lt;print&gt;</code> header: <code>std::print</code>, <code>std::println</code> (adds a new line) that uses <code>std::format</code> to output text to stdout. Plus lower-level routines like <code>vprint_unicode</code> with more parameters for output.</p> <h2 id="constexpr-to_chars-from_chars"> <code>constexpr</code> <code>to_chars()</code>, <code>from_chars()</code> <a class="hash-link" href="#constexpr-to_chars-from_chars" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2291">P2291</a></p> <p>Integral versions available in <code>constexpr</code> context:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;charconv&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;optional&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string_view&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">to_int</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">sv</span><span class="p">)</span> </span></span><span class="line"><span class="cl"><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">value</span> <span class="p">{};</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">from_chars</span><span class="p">(</span><span class="n">sv</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">sv</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">value</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">ret</span><span class="p">.</span><span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="p">{})</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">value</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{};</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">to_int</span><span class="p">(</span><span class="s">&#34;hello&#34;</span><span class="p">)</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">nullopt</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">to_int</span><span class="p">(</span><span class="s">&#34;10&#34;</span><span class="p">)</span> <span class="o">==</span> <span class="mi">10</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/aTPe9T7oE">@Compiler Explorer</a></p> <p>See my article about this new feature and more example: <a href="https://www.cppstories.com/2018/12/fromchars/#c23-updates">C++ String Conversion: Exploring std::from_chars in C++17 to C++26 - C++ Stories</a></p> <h2 id="standard-library-modules"> Standard Library Modules <a class="hash-link" href="#standard-library-modules" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2465">P2465</a></p> <p>C++23 introduces two standard library modules that significantly improve compilation efficiency and code organization:</p> <h4 id="import-std"> <code>import std;</code> </h4> <ul> <li>Imports all C++ standard library components in namespace <code>std</code></li> <li>Includes C++ headers and C wrapper headers</li> <li>Provides <code>::operator new</code> and related operators</li> <li>Keeps the global namespace clean</li> <li>Ideal for new projects and modern C++ code</li> </ul> <h4 id="import-stdcompat"> <code>import std.compat;</code> </h4> <ul> <li>Provides everything from <code>import std;</code></li> <li>Additionally, imports C functions into global namespace</li> <li>Helps transition legacy code that uses unqualified C functions</li> <li>Useful when working with platforms where C functions are traditionally global</li> <li>Recommended for compatibility with existing codebases</li> </ul> <p>Here are two examples:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">import</span> <span class="n">std</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">str</span> <span class="o">=</span> <span class="s">&#34;Hello&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">size_t</span> <span class="n">len</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">strlen</span><span class="p">(</span><span class="n">str</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span> <span class="c1">// must use std:: </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">println</span><span class="p">(</span><span class="s">&#34;Length: {}&#34;</span><span class="p">,</span> <span class="n">len</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>and the <code>compat</code> version:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">import</span> <span class="n">std</span><span class="p">.</span><span class="n">compat</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">str</span> <span class="o">=</span> <span class="s">&#34;Hello&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">len</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">(</span><span class="n">str</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span> <span class="c1">// works: strlen is global </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">printf</span><span class="p">(</span><span class="s">&#34;Length: %zu</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">len</span><span class="p">);</span> <span class="c1">// works: printf is global </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span></code></pre></div><p>Unfortunately as of December 2024, no major compiler supports the above examples.</p> <h2 id="stdgenerator-coroutine-generator"> <code>std::generator</code> Coroutine Generator <a class="hash-link" href="#stdgenerator-coroutine-generator" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2502">P2502</a></p> <p>C++20 introduced coroutines, but the standard library support was minimal, leaving us to implement our own coroutine types or rely on third-party libraries. Synchronous generators are a crucial use case for coroutines, enabling efficient and lazy evaluation of sequences. Writing an efficient recursive generator is non-trivial, and the standard should provide one to simplify this task for us.</p> <p><code>std::generator</code> fills this gap by providing a ready-to-use, standardized coroutine type for generating sequences. This makes it significantly easier for us to adopt coroutines in our projects without the overhead of implementing custom coroutine logic.</p> <p><code>std::generator</code> is a coroutine-based feature that uses the <code>co_yield</code> keyword to define a sequence of values. Each <code>co_yield</code> call produces a value and suspends execution, allowing us to retrieve the value. When resumed, the coroutine continues from where it left off.</p> <p>Here&rsquo;s a simple generator:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">generator</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">gen</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">a</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">a</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="k">co_yield</span> <span class="n">a</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">g</span> <span class="o">=</span> <span class="n">gen</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">g</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">while</span> <span class="p">(</span><span class="n">it</span> <span class="o">!=</span> <span class="n">g</span><span class="p">.</span><span class="n">end</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="o">*</span><span class="n">it</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="o">++</span><span class="n">it</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/MoMP6jeP4">@Compiler Explorer</a></p> <p>For more examples have a look at my two bonus articles for Patreons:</p> <ul> <li><a href="https://www.patreon.com/posts/114323519">std::generator in C++23: A Leap into Coroutines</a></li> <li><a href="https://www.patreon.com/posts/116586458">Building a custom coroutine generator, C++23</a></li> </ul> <h2 id="explicit-lifetime-management"> Explicit Lifetime Management <a class="hash-link" href="#explicit-lifetime-management" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2590">P2590</a>, <a href="https://wg21.link/P2679R2">P2679R2</a></p> <p>From the proposal:</p> <blockquote> <p>Since C++20, certain functions in the C++ standard library such as <code>malloc</code>, <code>bit_cast</code>, and <code>memcpy</code> are defined to implicitly create objects.</p> </blockquote> <p>But when you use non standard techniques to obtain a memory for the object you might end up with UB:</p> <p>C++23 introduces <code>std::start_lifetime_as/start_lifetime_as_array</code> to explicitly start the lifetime of objects in raw memory, enabling well-defined behavior without invoking constructors. This is useful for low-level tasks like custom allocators or deserialization.</p> <p>For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;memory&gt; </span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">X</span> <span class="p">{</span> <span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">example</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">void</span><span class="o">*</span> <span class="n">rawMemory</span> <span class="o">=</span> <span class="n">My_Malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">X</span><span class="p">));</span> <span class="c1">// non standard way... </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">X</span><span class="o">*</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">start_lifetime_as</span><span class="o">&lt;</span><span class="n">X</span><span class="o">&gt;</span><span class="p">(</span><span class="n">rawMemory</span><span class="p">);</span> <span class="c1">// Start lifetime </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">obj</span><span class="o">-&gt;</span><span class="n">a</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span> <span class="n">obj</span><span class="o">-&gt;</span><span class="n">b</span> <span class="o">=</span> <span class="mi">84</span><span class="p">;</span> <span class="c1">// Use the object </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">free</span><span class="p">(</span><span class="n">rawMemory</span><span class="p">);</span> <span class="c1">// Free memory </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span></code></pre></div><p>(as of December no major compiler implements this functionality)</p> <h2 id="spanstream-string-stream-with-span-buffers"> <code>&lt;spanstream&gt;</code> String-Stream with Span Buffers <a class="hash-link" href="#spanstream-string-stream-with-span-buffers" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P0448">P0448</a></p> <p>New classes: <code>basic_spanbuf</code>, <code>basic_ispanstream</code>, <code>basic_ospanstream</code>, <code>basic_spanstream</code> analogous to existing stream classes but using <code>std::span</code> as the buffer. They allow explicit buffer management and improved performance.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">64</span><span class="p">]</span> <span class="p">{</span> <span class="mi">0</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">span</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">spanBuffer</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">basic_ospanstream</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span> <span class="n">outputStream</span><span class="p">(</span><span class="n">spanBuffer</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">outputStream</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Hello, &#34;</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;C++23!&#34;</span><span class="p">;</span> </span></span></code></pre></div><h2 id="stdformat-improvements"> <code>std::format</code> Improvements <a class="hash-link" href="#stdformat-improvements" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li>Compile-time string parsing - <a href="https://wg21.link/P2216R3">P2216R3</a></li> <li>Formatting Ranges - <a href="https://wg21.link/P2286R8">P2286R8</a></li> <li>Improve default container formatting - <a href="https://wg21.link/P2585R1">P2585R1</a></li> <li>Formatting std::thread::id and std::stacktrace - <a href="https://wg21.link/P2693R1">P2693R1</a></li> <li>Add support for non-const-formattable types to std::format - <a href="https://wg21.link/P2418R2">P2418R2</a></li> </ul> <h2 id="stdvisit-for-classes-derived-from-stdvariant"> <code>std::visit()</code> for classes derived from <code>std::variant</code> <a class="hash-link" href="#stdvisit-for-classes-derived-from-stdvariant" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2162">P2162</a></p> <p>Just see the example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;variant&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;memory&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Connecting</span> <span class="p">{};</span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Connected</span> <span class="p">{};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">State</span> <span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="n">Connecting</span><span class="p">,</span> <span class="n">Connected</span><span class="o">&gt;</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="n">Connecting</span><span class="p">,</span> <span class="n">Connected</span><span class="o">&gt;::</span><span class="n">variant</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="kt">bool</span> <span class="nf">is_connected</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">holds_alternative</span><span class="o">&lt;</span><span class="n">Connected</span><span class="o">&gt;</span><span class="p">(</span><span class="o">*</span><span class="k">this</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">StateVisitor</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">operator</span><span class="p">()(</span><span class="n">Connecting</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;State: Connecting</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="kt">void</span> <span class="nf">operator</span><span class="p">()(</span><span class="n">Connected</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;State: Connected</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">State</span> <span class="n">state</span> <span class="o">=</span> <span class="n">Connecting</span><span class="p">{};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">visit</span><span class="p">(</span><span class="n">StateVisitor</span><span class="p">{},</span> <span class="n">state</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">state</span><span class="p">.</span><span class="n">is_connected</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;The system is connected.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;The system is not connected.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/91795z3s4">@Compiler Explorer</a></p> <p>The class <code>State</code> inherits from <code>std::variant</code> and before this proposal there was no way to use <code>std::visit</code> on such a class. Right now it&rsquo;s possible and allows us to reduce some extra code.</p> <p>This fix can be implemented against C++17.</p> <h2 id="stdunreachable"> <code>std::unreachable()</code> <a class="hash-link" href="#stdunreachable" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P0627">P0627</a></p> <p>The proposal introduces a new function, <code>std::unreachable</code>, to the C++ standard library. This function is designed to mark code locations that the programmer knows are unreachable, allowing the compiler to optimize by eliminating unnecessary checks. This function might be particularly useful for you in scenarios where the compiler cannot deduce that certain code paths are impossible, such as in fully covered switch statements or functions that never return.</p> <p>The functionality also standardizes existing vendor-specific approaches like <code>__builtin_unreachable()</code> in GCC and Clang, or <code>__assume(false)</code> in MSVC.</p> <h2 id="deprecating-stdaligned_storage-and-aligned_union"> Deprecating <code>std::aligned_storage</code> and <code>aligned_union</code> <a class="hash-link" href="#deprecating-stdaligned_storage-and-aligned_union" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P1413R3">P1413</a></p> <p>The accepted proposal deprecates C++11&rsquo;s <code>std::aligned_storage</code> and <code>std::aligned_union</code> in the C++ standard due to their poor API design, undefined behavior risks, and limited utility. These helper types require error-prone usage patterns like <code>reinterpret_cast</code>, lack proper size guarantees, and have inconsistent or confusing APIs, making them unsuitable for modern C++ practices.</p> <p>The authors analysed libraries like Boost, Folly, and Abseil and most use cases for <code>std::aligned_</code> involve repetitive patterns to deduce size and alignment manually. This can be replaced with simpler alternatives like <code>alignas</code> and <code>std::byte</code> arrays.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// deprecated: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MyContainer</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">aligned_storage_t</span><span class="o">&lt;</span><span class="k">sizeof</span><span class="p">(</span><span class="n">T</span><span class="p">),</span> <span class="k">alignof</span><span class="p">(</span><span class="n">T</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">buffer</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// better: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MyContainer</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">alignas</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="n">std</span><span class="o">::</span><span class="n">byte</span> <span class="n">buffer</span><span class="p">[</span><span class="k">sizeof</span><span class="p">(</span><span class="n">T</span><span class="p">)];</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span></code></pre></div><p>These utilities are still available in the standard but are marked as discouraged for use. They may be removed in a future version of the standard (e.g., C++26 or later).</p> <p>For example clang reports <code>warning: 'aligned_storage_t' is deprecated</code> when compiling in C++23 mode.</p> <h2 id="pipe-support-for-user-defined-range-adaptors"> Pipe support for user-defined range adaptors, <a class="hash-link" href="#pipe-support-for-user-defined-range-adaptors" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2387">P2387</a></p> <p>The proposal introduces a standardized mechanism in C++23 to enable user-defined range adaptors to interoperate seamlessly with the standard library&rsquo;s range adaptors and other user-defined adaptors. This is achieved by providing a base class, <code>std::ranges::range_adaptor_closure</code>, which simplifies the creation of custom range adaptors that support the pipe <code>(|)</code> operator. Additionally, the proposal introduces <code>std::bind_back</code>, a utility for partial function application.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ranges&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="c1">// Custom range adaptor closure </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">struct</span> <span class="nc">double_values_closure</span> </span></span><span class="line"><span class="cl"><span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">range_adaptor_closure</span><span class="o">&lt;</span><span class="n">double_values_closure</span><span class="o">&gt;</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">template</span> <span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">viewable_range</span> <span class="n">R</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"> <span class="k">constexpr</span> <span class="k">auto</span> <span class="k">operator</span><span class="p">()(</span><span class="n">R</span><span class="o">&amp;&amp;</span> <span class="n">range</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">transform_view</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">R</span><span class="o">&gt;</span><span class="p">(</span><span class="n">range</span><span class="p">),</span> <span class="p">[](</span><span class="k">auto</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> <span class="p">});</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kr">inline</span> <span class="k">constexpr</span> <span class="n">double_values_closure</span> <span class="n">double_values</span><span class="p">{};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">numbers</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">doubled</span> <span class="o">=</span> <span class="n">numbers</span> <span class="o">|</span> <span class="n">double_values</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="nl">n</span> <span class="p">:</span> <span class="n">doubled</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">n</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/65Pa7TGY7">@Compiler Explorer</a></p> <h2 id="stdmove_only_function"> <code>std::move_only_function</code> <a class="hash-link" href="#stdmove_only_function" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P0288">P0288</a> and more story in early proposal: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4543.pdf">N4543</a> (PDF)</p> <p>The <code>std::move_only_function</code> is a move-only equivalent of <code>std::function</code>. It provides a type-erased wrapper for callable objects, supporting cv/ref/noexcept-qualified function types while avoiding the const-correctness issues of <code>std::function</code>. Unlike <code>std::function</code>, it does not support <code>target</code> or <code>target_type</code> accessors, ensuring a simpler and more efficient design. This feature is particularly useful for scenarios where callable objects need to be moved rather than copied, such as in asynchronous programming or resource-constrained environments. The proposal encourages small-object optimization to avoid dynamic memory allocation for small callable objects.</p> <h2 id="books-on-c23"> Books on C++23 <a class="hash-link" href="#books-on-c23" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Although the standard is fresh, there are several good books focusing on C++23 worth reading&hellip; and probably more to come :)</p> <table> <thead> <tr> <th>Title</th> <th>Author(s)</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td><a href="https://amzn.to/3UYGRAI">Modern C++ Programming Cookbook (3rd Edition)</a></td> <td>Marius Bancila</td> <td>Master Modern C++ with comprehensive solutions for C++23 and all previous standards</td> </tr> <tr> <td><a href="https://amzn.to/4fAwE5Y">The C++ Programming Language (4th Edition)</a></td> <td>Bjarne Stroustrup</td> <td>The definitive guide from the creator of C++</td> </tr> <tr> <td><a href="https://amzn.to/4eKqNcR">Beginning C++23: From Beginner to Pro (7th Edition)</a></td> <td>Ivor Horton, Peter Van Weert</td> <td>A comprehensive guide for learning modern C++ from the ground up</td> </tr> <tr> <td><a href="https://amzn.to/4eD1MR6">Modern C++ for Absolute Beginners (2nd Edition)</a></td> <td>Slobodan Dmitrović</td> <td>A friendly introduction to C++ programming language and C++11 to C++23 standards</td> </tr> <tr> <td><a href="https://amzn.to/3YWRGEL">C++23 Best Practices</a></td> <td>Jason Turner</td> <td>Simple rules with specific action items for better C++</td> </tr> <tr> <td><a href="https://amzn.to/3Zi3Byt">Learn C++ by Example</a></td> <td>Frances Buontempo</td> <td>A practical approach to learning C++ versions 11 to 23</td> </tr> </tbody> </table> <p><em>Note: Links are affiliate links and may provide the site with a small commission at no extra cost to you.</em></p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>I hope we covered most, if not all, C++23 library features!</p> <p>You can check their implementation status at C++ Reference: <a href="https://en.cppreference.com/w/cpp/compiler_support#cpp23">https://en.cppreference.com/w/cpp/compiler_support#cpp23</a></p> <p>For language features please see the previous article: <a href="https://www.cppstories.com/2024/cpp23_lang/">C++23 Language Features and Reference Cards - C++ Stories</a></p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Have you played with C++23 library features?</li> <li>What are the most important features for you in this release?</li> </ul> C++23 Language Features and Reference Cards https://www.cppstories.com/2024/cpp23_lang/ Sun, 17 Nov 2024 00:00:00 +0000 https://www.cppstories.com/2024/cpp23_lang/ <h1 id="c23-language-features"> C++23 Language Features <a class="hash-link" href="#c23-language-features" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h1> <p>In this blog post, you&rsquo;ll see all C++23 language features! Each with short description and additional code example.</p> <p>Prepare for a ride!</p> <blockquote class="hint note"> For library features please see the next article: <a href="https://www.cppstories.com/2024/cpp23_lib/">C++23 Library Features and Reference Cards - C++ Stories</a> </blockquote> <h2 id="want-your-own-copy-to-print"> Want your own copy to print? <a class="hash-link" href="#want-your-own-copy-to-print" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>If you like, I prepared PDF I packed both language and the Standard Library features. Each one has a short description and an example if possible.</p> <p><img src="../../images/2017cards.PNG" alt=""></p> <p>All of the existing subscribers of my mailing list have already got the new document, so If you want to download it just subscribe here:</p> <div style="width:80%;background-color:#fafafa;border-top:solid 1px #ef8f00;border-bottom:solid 1px #ef8f00;margin-left:auto;margin-right:auto;"> <div style="text-align:center;margin:1em 0 1em 0;"> <a style="color: #ffffff; text-decoration: none; font-family: Helvetica, Arial, sans-serif; font-weight: bold; font-size: 16px; line-height: 20px; padding: 10px; display: inline-block; max-width: 500px; text-shadow: rgba(0, 0, 0, 0.247059) 0px -1px 1px; box-shadow: rgba(255, 255, 255, 0.498039) 0px 1px 3px inset, rgba(0, 0, 0, 0.498039) 0px 1px 3px; background: #ef8f00;" href="http://eepurl.com/cyycFz" target="_blank">Download a free copy of C++23 Ref Card!</a> </div> </div> <p>Please notice that along with the new ref card you&rsquo;ll also get C++20 and C++17 language reference card that I initially published three years ago. With this &ldquo;package&rdquo; you&rsquo;ll quickly learn about all of the latest parts that Modern C++ acquired over the last few years.</p> <h2 id="timeline"> Timeline <a class="hash-link" href="#timeline" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Here&rsquo;s a short overview about the timeline for the new standard.</p> <ul> <li><strong>February 2020</strong> (Prague): Final C++20 meeting where initial plans for C++23 were adopted <ul> <li>Key planned features: library support for coroutines, modular standard library, executors, and networking</li> </ul> </li> <li><strong>June 2020</strong>: First planned WG21 meeting for C++23 in Varna was cancelled due to COVID-19 pandemic</li> <li><strong>November 2020</strong>: New York meeting cancelled, moved to virtual format <ul> <li>Key additions: size_t literals, stacktrace library, contains() member functions, C atomic interoperability</li> </ul> </li> <li><strong>February 2021</strong>: Virtual meeting <ul> <li>Notable features: Lambda expression simplifications, variant improvements, conditionally borrowed ranges</li> </ul> </li> <li><strong>June 2021</strong>: Virtual summer plenary meeting <ul> <li>Major additions: if consteval, spanstream, out_ptr/inout_ptr, constexpr improvements</li> </ul> </li> <li><strong>October 2021</strong>: Virtual autumn plenary meeting <ul> <li>Significant features: Explicit this parameter, multidimensional subscript operator, zip ranges</li> </ul> </li> <li><strong>February 2022</strong>: Virtual meeting <ul> <li>Key additions: std::expected, ranges::to, windowing range adaptors</li> </ul> </li> <li><strong>July 2022</strong>: Virtual meeting <ul> <li>Major features: static operator(), UTF-8 source files, std::mdspan, flat containers</li> </ul> </li> <li><strong>November 2022</strong>: First hybrid meeting <ul> <li>Notable additions: Static operator[], lifetime extensions for range-based for loops</li> </ul> </li> <li><strong>February 2023</strong>: Final hybrid meeting in Issaquah <ul> <li>Technical content finalized</li> <li>Last features added: views::enumerate, formatting improvements, std::barrier guarantees</li> </ul> </li> <li><strong>October 2024:</strong> Published with a long delay at ISO: as <a href="https://www.iso.org/standard/83626.html">ISO/IEC 14882:2024 - Programming languages — C++</a></li> </ul> <p>Now let&rsquo;s jump into the features:</p> <h2 id="if-consteval--"> <code>if consteval { }</code> <a class="hash-link" href="#if-consteval--" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P1938">P1938</a></p> <p>The new syntax is equivalent to the following code from C++20:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_constant_evaluated</span><span class="p">())</span> <span class="p">{</span> <span class="p">}</span> </span></span></code></pre></div><p>It’s a language feature now, so no need for a separate header. It can call <code>consteval</code> functions and it is easier to understand.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="kt">int</span> <span class="nf">run</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="k">consteval</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">i</span><span class="o">*</span><span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">i</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">run</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="o">==</span> <span class="mi">20</span><span class="p">);</span> <span class="c1">// compile-time </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">run</span><span class="p">(</span><span class="n">a</span><span class="p">);</span> <span class="c1">// run-time </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/4KG7rKqv1">@Compiler Explorer</a></p> <h2 id="deducing-this"> Deducing <code>this</code> <a class="hash-link" href="#deducing-this" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P0847">P0847</a></p> <p>A way to explicitly pass the <code>this</code> parameter into a member function, allowing for more control and reduces code duplication. You can pass <code>this</code> by value, call lambdas recursively, simplify the CRTP pattern, and more.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Pattern</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Self</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">foo</span><span class="p">(</span><span class="k">this</span> <span class="n">Self</span><span class="o">&amp;&amp;</span> <span class="n">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">self</span><span class="p">.</span><span class="n">fooImpl</span><span class="p">();</span> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">MyClass</span> <span class="o">:</span> <span class="n">Pattern</span> <span class="p">{</span> <span class="kt">void</span> <span class="nf">fooImpl</span><span class="p">()</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span> <span class="p">};</span> </span></span></code></pre></div><p>See my examples at this Patreon post: <a href="https://www.patreon.com/posts/110268551">C++23: Deducing This, a few examples</a> (Available for all patrons, even at the free tier).</p> <h2 id="autox-and-autox"> <code>auto(x)</code> and <code>auto{x}</code> <a class="hash-link" href="#autox-and-autox" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P0849">P0849</a></p> <p>Replaces <code>decay_copy</code> (an internal library helper) with a language feature. Allows creating a decay rvalue copy of the input object.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">pop_front_alike</span><span class="p">(</span><span class="n">Container</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">T</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">front</span><span class="p">())</span><span class="o">&gt;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">erase</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">x</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">T</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">front</span><span class="p">()));</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="c1">// becomes: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">erase</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">x</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="k">auto</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">front</span><span class="p">()));</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">str</span> <span class="o">=</span> <span class="s">&#34;hello&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span><span class="p">(</span><span class="n">str</span><span class="p">);</span> <span class="c1">// Creates a new std::string (decayed copy) </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span><span class="p">(</span><span class="n">arr</span><span class="p">);</span> <span class="c1">// Creates int* (arrays decay to pointers) </span></span></span></code></pre></div><h2 id="extend-init-statement-to-allow-alias-declaration"> Extend init-statement to allow alias-declaration <a class="hash-link" href="#extend-init-statement-to-allow-alias-declaration" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2360">P2360</a></p> <p>In C++20, <code>using</code> wasn’t allowed in the for loop, now it’s possible:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="k">using</span> <span class="n">T</span> <span class="o">=</span> <span class="kt">int</span><span class="p">;</span> <span class="n">T</span> <span class="nl">e</span> <span class="p">:</span> <span class="n">container</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span> </span></span></code></pre></div><h2 id="multidimensional-subscript-operator"> Multidimensional Subscript Operator <a class="hash-link" href="#multidimensional-subscript-operator" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2128">P2128</a></p> <p>Change the rules to allow multiple parameters for <code>operator[]</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Array2D</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">m</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">size_t</span> <span class="n">w</span><span class="p">,</span> <span class="n">h</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="n">Array2D</span><span class="p">(</span><span class="n">size_t</span> <span class="n">width</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">height</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">:</span> <span class="n">m</span><span class="p">(</span><span class="n">width</span> <span class="o">*</span> <span class="n">height</span><span class="p">),</span> <span class="n">w</span><span class="p">(</span><span class="n">width</span><span class="p">),</span> <span class="n">h</span><span class="p">(</span><span class="n">height</span><span class="p">)</span> <span class="p">{}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">T</span><span class="o">&amp;</span> <span class="k">operator</span><span class="p">[](</span><span class="n">size_t</span> <span class="n">i</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">j</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">m</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">j</span> <span class="o">*</span> <span class="n">w</span><span class="p">];</span> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Array2D</span><span class="o">&lt;</span><span class="kt">float</span><span class="o">&gt;</span> <span class="n">arr</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">arr</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.0f</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/WGnM4o89E">@Compiler Explorer</a></p> <p>This is crucial for types like <code>std::mdspan</code>.</p> <h2 id="static-operator-and-static-operator-"> <code>static operator()</code> and <code>static operator []</code> <a class="hash-link" href="#static-operator-and-static-operator-" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P1169R4">P1169R4</a> and <a href="https://wg21.link/P2589R1">P2589R1</a></p> <p>Allows for more optimization in the compiler. The call operator is especially handy for captureless lambdas. The compiler can optimize away passing the “this” pointer to the call. You can specify a lambda to be static.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Fn</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">constexpr</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">x</span><span class="o">*</span><span class="mi">10</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">Fn</span><span class="o">::</span><span class="k">operator</span><span class="p">()(</span><span class="mi">10</span><span class="p">)</span> <span class="o">==</span> <span class="mi">100</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">Fn</span> <span class="n">x</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">x</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="o">==</span> <span class="mi">100</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/GWqchPEWW">@Compiler Explorer</a></p> <h2 id="features-for-lambdas"> Features for Lambdas <a class="hash-link" href="#features-for-lambdas" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li>Attributes on lambdas</li> <li><code>()</code> is more optional - <a href="https://wg21.link/P1102">P1102</a></li> <li>The call operator can be <code>static</code></li> <li>Deducing <code>this</code> adds new capabilities like better recursion</li> <li>Change scope of lambda trailing-return-type</li> </ul> <p>Examples:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">identity</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="k">static</span> <span class="p">{</span> <span class="k">return</span> <span class="n">x</span><span class="p">;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">identity</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/3jaToKzGq">@Compiler Explorer</a></p> <p>Recursive lambda:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">fib</span> <span class="o">=</span> <span class="p">[](</span><span class="k">this</span> <span class="k">auto</span> <span class="n">self</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">)</span> <span class="k">return</span> <span class="n">n</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">self</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">self</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">fib</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span> <span class="o">==</span> <span class="mi">13</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/8vaTczcPs">@Compiler Explorer</a></p> <p>Optional <code>()</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">fn</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">]</span> <span class="k">mutable</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">x</span><span class="o">++</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">fn</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="n">fn</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/EhE6zdoa3">@Compiler Explorer</a></p> <h2 id="assume-new-attribute"> [[assume]] New Attribute <a class="hash-link" href="#assume-new-attribute" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P1774">P1774</a></p> <p><code>[[assume]]</code> specifies that an expression will always evaluate to true at a given point. It standardizes the existing vendor-specific semantics like <code>__builtin_assume</code> (Clang) and <code>__assume</code> (MSVC, ICC). Offers potential optimization opportunities for compilers. If the assumption turns out to be false during runtime, the behavior is <strong>undefined</strong>, making it crucial to use this attribute only when absolutely certain about the condition.</p> <p>The attribute can help compilers eliminate unnecessary bounds checking, enable better loop optimizations, and remove redundant error handling paths.</p> <p>For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Basic usage - compiler can optimize sqrt calculation </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">void</span> <span class="nf">process_positive</span><span class="p">(</span><span class="kt">double</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="na">[[assume(x &gt;= 0)]]</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">sqrt</span><span class="p">(</span><span class="n">x</span><span class="p">);</span> <span class="c1">// No need for negative number checks </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// Loop optimization example </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">void</span> <span class="nf">process_array</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span> <span class="n">arr</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">size</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="na">[[assume(size % 4 == 0)]]</span><span class="p">;</span> <span class="c1">// Assume size is multiple of 4 </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="na">[[assume(size &gt; 0)]]</span><span class="p">;</span> <span class="c1">// Assume non-empty array </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">size</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Compiler can optimize for 4-element chunks </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// No need for remainder handling </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">arr</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">arr</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">arr</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">arr</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">3</span><span class="p">]</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><h2 id="constexpr-updates"> Constexpr Updates <a class="hash-link" href="#constexpr-updates" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2448">P2448</a>, <a href="https://wg21.link/P2647">P2647</a>, and <a href="https://wg21.link/P2242">P2242</a></p> <ul> <li>Relax rules for constructors and return types for <code>constexpr</code> functions, making them almost identical to regular functions.</li> <li>Permitting static <code>constexpr</code> variables in <code>constexpr</code> functions.</li> </ul> <h2 id="extend-lifetime-of-temporaries-in-range-based-for"> Extend Lifetime of Temporaries in Range-Based For <a class="hash-link" href="#extend-lifetime-of-temporaries-in-range-based-for" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2718">P2718</a></p> <p>This is a very popular and long-standing proposal that generated significant discussion in the C++ community. While initially aimed at addressing all temporary lifetime issues, it was ultimately restricted to focus on range-based for loops, where the problem was most acute and the solution most clear-cut.</p> <p>The change extends the lifetime of temporary objects in the for-range-initializer until the end of the loop. This fixes a common source of undefined behavior that many developers encountered, especially when working with chain calls or complex expressions.</p> <p>Before C++23:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Undefined Behavior in C++20 and earlier: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">getVector</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">e</span> <span class="p">:</span> <span class="n">getVector</span><span class="p">()[</span><span class="mi">0</span><span class="p">])</span> <span class="p">{</span> <span class="c1">// temporary vector destroyed here! </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> <span class="c1">// accessing destroyed object </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// Workaround required in C++20: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">getVector</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">e</span> <span class="p">:</span> <span class="n">temp</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>C++23 makes the first version safe and equivalent to the workaround:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Now valid in C++23: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">e</span> <span class="p">:</span> <span class="n">getVector</span><span class="p">()[</span><span class="mi">0</span><span class="p">])</span> <span class="p">{</span> <span class="c1">// temporary vector lives through the loop </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// More complex example that&#39;s now safe: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">struct</span> <span class="nc">Matrix</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="nf">getRow</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="cm">/* ... */</span><span class="p">;</span> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Matrix</span><span class="o">&gt;</span> <span class="n">matrices</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">val</span> <span class="p">:</span> <span class="n">matrices</span><span class="p">.</span><span class="n">back</span><span class="p">().</span><span class="n">getRow</span><span class="p">(</span><span class="mi">42</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Both the temporary from back() and getRow() are preserved </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">process</span><span class="p">(</span><span class="n">val</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>This change significantly improves the safety and usability of range-based for loops, eliminating a common class of bugs while maintaining the expressive power of the syntax. However, it&rsquo;s important to note that this fix is specific to range-based for loops and doesn&rsquo;t address temporary lifetime issues in other contexts.</p> <h2 id="new-preprocessor-directives"> New Preprocessor Directives <a class="hash-link" href="#new-preprocessor-directives" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2334">P2334</a> and <a href="https://wg21.link/P2437">P2437</a></p> <p>C++23 introduces two sets of new preprocessor directives that improve code readability and maintain compatibility with C23. The <code>#elifdef</code> and <code>#elifndef</code> directives simplify conditional compilation chains, while <code>#warning</code> provides a standardized way to emit compiler warnings.</p> <p>These additions reduce verbosity and make the code more maintainable compared to traditional preprocessor constructs.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Old style: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#ifdef _WIN32 </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#define PLATFORM &#34;Windows&#34; </span></span></span><span class="line"><span class="cl"><span class="cp">#else </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#ifdef __linux__ </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#define PLATFORM &#34;Linux&#34; </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#else </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#ifdef __APPLE__ </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#define PLATFORM &#34;macOS&#34; </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#endif </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#endif </span></span></span><span class="line"><span class="cl"><span class="cp">#endif </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="c1">// New style in C++23: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#ifdef _WIN32 </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#define PLATFORM &#34;Windows&#34; </span></span></span><span class="line"><span class="cl"><span class="cp">#elifdef __linux__ </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#define PLATFORM &#34;Linux&#34; </span></span></span><span class="line"><span class="cl"><span class="cp">#elifdef __APPLE__ </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#define PLATFORM &#34;macOS&#34; </span></span></span><span class="line"><span class="cl"><span class="cp">#else </span></span></span><span class="line"><span class="cl"><span class="cp"></span> <span class="cp">#warning &#34;Unknown platform detected!&#34; </span></span></span><span class="line"><span class="cl"><span class="cp">#endif </span></span></span></code></pre></div><p>The new directives are particularly useful in cross-platform code and library compatibility checks, making conditional compilation more straightforward and easier to maintain.</p> <h2 id="literal-suffix-for-signed-size_t--uz-uz"> Literal Suffix for (Signed) size_t – uz, UZ <a class="hash-link" href="#literal-suffix-for-signed-size_t--uz-uz" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P0330">P0330</a></p> <p>A simple yet effective fix for various numerical conversions between integer types, unsigned, and size_t which is commonly returned from std:: containers. The feature introduces three new literal suffixes:</p> <ul> <li>uz or UZ for size_t</li> <li>z or Z for the signed counterpart (ptrdiff_t or equivalent)</li> </ul> <p>This addition eliminates common warnings and potential bugs related to signed/unsigned mismatches, particularly in loop counters and container operations.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Before C++23 - potential warnings or issues: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">vec</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="c1">// warning: comparison between signed/unsigned </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">vec</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="c1">// verbose </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"><span class="c1">// C++23 - clean and portable: </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0u</span><span class="n">z</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">vec</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="c1">// perfect match with container&#39;s size_t </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">i</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">vec</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span></code></pre></div><p>The feature is particularly valuable for writing portable code that needs to work correctly across different platforms and architectures, automatically adapting to the platform&rsquo;s size_t width without explicit type specifications.</p> <h2 id="ctad-from-inherited-constructors"> CTAD from inherited constructors <a class="hash-link" href="#ctad-from-inherited-constructors" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2582R1">P2582R1</a></p> <p>C++23 extends Class Template Argument Deduction to work with inherited constructors, filling an important gap in CTAD functionality. This allows template arguments to be deduced when using inherited constructors through using declarations.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Before C++23 - CTAD didn&#39;t work with inherited constructors </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Base</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Base</span><span class="p">(</span><span class="n">T</span> <span class="n">value</span><span class="p">)</span> <span class="p">{}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Derived</span> <span class="o">:</span> <span class="n">Base</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="n">Base</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">Base</span><span class="p">;</span> <span class="c1">// Inherit constructor </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">Derived</span> <span class="nf">d</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span> <span class="c1">// Error in C++20: couldn&#39;t deduce T </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// OK in C++23: deduces Derived&lt;int&gt; </span></span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/oon7KGvYM">@Compiler Explorer</a></p> <p>This feature makes template class hierarchies more intuitive to use and eliminates the need for explicit template arguments when using inherited constructors, improving code readability and maintainability.</p> <h2 id="simpler-implicit-move"> Simpler implicit move <a class="hash-link" href="#simpler-implicit-move" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><a href="https://wg21.link/P2266">P2266</a></p> <p>C++23 simplifies and fixes the implicit move rules introduced in C++20, making them more consistent and easier to implement. The new rules state that a move-eligible id-expression is always treated as an xvalue, eliminating the previous two-step overload resolution process.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Before C++23 - inconsistent behavior </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">Widget</span><span class="o">&amp;&amp;</span> <span class="n">foo</span><span class="p">(</span><span class="n">Widget</span><span class="o">&amp;&amp;</span> <span class="n">w</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">w</span><span class="p">;</span> <span class="c1">// Error in C++20 </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">};</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/arv11a7re">@Compiler Explorer</a></p> <h2 id="drs"> DRs <a class="hash-link" href="#drs" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Here&rsquo;s the formatted list of C++23 DRs:</p> <p>These Defect Reports (DRs) are actually retroactive fixes that apply to C++20 as well as C++23:</p> <ol> <li><strong>Lambda Trailing-Return-Type Scope Change</strong> (<a href="https://wg21.link/P2036R3">P2036R3</a>, <a href="https://wg21.link/P2579R0">P2579R0</a>) <ul> <li>Changes the scope rules for lambda expression trailing return types</li> </ul> </li> <li><strong>Meaningful Exports</strong> (<a href="https://wg21.link/P2615R1">P2615R1</a>) <ul> <li>Improves the semantics of export declarations in modules</li> </ul> </li> <li><strong>Consteval Propagation</strong> (<a href="https://wg21.link/P2564R0">P2564R0</a>) <ul> <li>Fixes issues with consteval propagation in the language</li> </ul> </li> <li><strong>Unicode Identifier Syntax</strong> (<a href="https://wg21.link/P1949R7">P1949R7</a>) <ul> <li>Updates C++ identifier syntax to align with Unicode Standard Annex 31</li> </ul> </li> <li><strong>Duplicate Attributes</strong> (<a href="https://wg21.link/P2156R1">P2156R1</a>) <ul> <li>Allows multiple instances of the same attribute in declarations</li> </ul> </li> <li><strong>Concepts Feature Test Macro</strong> (<a href="https://wg21.link/P2493R0">P2493R0</a>) <ul> <li>Adjusts the value of <code>__cpp_concepts</code> feature test macro</li> </ul> </li> <li><strong>Wchar_t Requirements</strong> (<a href="https://wg21.link/P2460R2">P2460R2</a>) <ul> <li>Relaxes requirements on wchar_t to match existing implementation practices</li> </ul> </li> <li><strong>Unknown Pointers in Constant Expressions</strong> (<a href="https://wg21.link/P2280R4">P2280R4</a>) <ul> <li>Allows using unknown pointers and references in constant expressions</li> </ul> </li> <li><strong>Equality Operator Enhancement</strong> (<a href="https://wg21.link/P2468R2">P2468R2</a>) <ul> <li>Improves equality operator behavior</li> </ul> </li> <li><strong>char8_t Compatibility</strong> (<a href="https://wg21.link/P2513R4">P2513R4</a>) <ul> <li>Enhances char8_t compatibility and portability</li> </ul> </li> <li><strong>Diagnostic Directives Clarification</strong> (<a href="https://cplusplus.github.io/CWG/issues/2518.html">CWG2518</a>) <ul> <li>Clarifies reporting of diagnostic directives and static_assert behavior in templates</li> </ul> </li> </ol> <h2 id="books-on-c23"> Books on C++23 <a class="hash-link" href="#books-on-c23" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Although the standard is fresh, there are several good books focusing on C++23 worth reading&hellip; and probably more to come :)</p> <table> <thead> <tr> <th>Title</th> <th>Author(s)</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td><a href="https://amzn.to/3UYGRAI">Modern C++ Programming Cookbook (3rd Edition)</a></td> <td>Marius Bancila</td> <td>Master Modern C++ with comprehensive solutions for C++23 and all previous standards</td> </tr> <tr> <td><a href="https://amzn.to/4fAwE5Y">The C++ Programming Language (4th Edition)</a></td> <td>Bjarne Stroustrup</td> <td>The definitive guide from the creator of C++</td> </tr> <tr> <td><a href="https://amzn.to/4eKqNcR">Beginning C++23: From Beginner to Pro (7th Edition)</a></td> <td>Ivor Horton, Peter Van Weert</td> <td>A comprehensive guide for learning modern C++ from the ground up</td> </tr> <tr> <td><a href="https://amzn.to/4eD1MR6">Modern C++ for Absolute Beginners (2nd Edition)</a></td> <td>Slobodan Dmitrović</td> <td>A friendly introduction to C++ programming language and C++11 to C++23 standards</td> </tr> <tr> <td><a href="https://amzn.to/3YWRGEL">C++23 Best Practices</a></td> <td>Jason Turner</td> <td>Simple rules with specific action items for better C++</td> </tr> <tr> <td><a href="https://amzn.to/3Zi3Byt">Learn C++ by Example</a></td> <td>Frances Buontempo</td> <td>A practical approach to learning C++ versions 11 to 23</td> </tr> </tbody> </table> <p><em>Note: Links are affiliate links and may provide the site with a small commission at no extra cost to you.</em></p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>I hope we covered most if not all C++23 language features!</p> <p>You can check their implementation status at C++ Reference: <a href="https://en.cppreference.com/w/cpp/compiler_support#cpp23">https://en.cppreference.com/w/cpp/compiler_support#cpp23</a></p> <p>And next time we&rsquo;ll handle Standard Library changes - see it here: <a href="https://www.cppstories.com/2024/cpp23_lib/">C++23 Library Features and Reference Cards - C++ Stories</a></p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Have you played with C++23?</li> <li>What are the most important features for you in this release?</li> </ul> Around the World in C++: Exploring Time Zones with std::chrono https://www.cppstories.com/2024/zones_around_world_chrono/ Sun, 10 Nov 2024 00:00:00 +0000 https://www.cppstories.com/2024/zones_around_world_chrono/ <p>While most time zones use simple hour offsets from UTC, some regions have chosen unusual time differences. In this blog post, we&rsquo;ll explore how we can discover such zones using C++20&rsquo;s chrono library.</p> <p>We&rsquo;ll use GCC 14.2 as it fully supports C++20 chrono and also <code>std::print</code> from C++23.</p> <h2 id="first-attempt-basic-zone-iteration"> First Attempt: Basic Zone Iteration <a class="hash-link" href="#first-attempt-basic-zone-iteration" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>C++20 introduced comprehensive time zone support through the <code>&lt;chrono&gt;</code> library. The implementation relies on the IANA Time Zone Database (also known as the &ldquo;tz database&rdquo; or &ldquo;zoneinfo&rdquo;), which is the de facto standard for time zone information used by most operating systems and programming languages.</p> <h3 id="the-time-zone-database"> The Time Zone Database <a class="hash-link" href="#the-time-zone-database" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>In C++20, the time zone database is represented by the <code>tzdb</code> class:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">struct</span> <span class="nc">tzdb</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">string</span> <span class="n">version</span><span class="p">;</span> <span class="c1">// IANA time zone database version </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">time_zone</span><span class="o">&gt;</span> <span class="n">zones</span><span class="p">;</span> <span class="c1">// Time zone container </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">time_zone_link</span><span class="o">&gt;</span> <span class="n">links</span><span class="p">;</span> <span class="c1">// Alternative names </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">leap_second</span><span class="o">&gt;</span> <span class="n">leap_seconds</span><span class="p">;</span> <span class="c1">// Leap second info </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Essential aspects of the database:</p> <ul> <li>It&rsquo;s read-only - users cannot construct or modify a <code>tzdb</code></li> <li>Access is provided through two global functions: <ul> <li><code>get_tzdb()</code>: Returns the current database</li> <li><code>get_tzdb_list()</code>: Returns the list of available database versions</li> </ul> </li> </ul> <p>Here&rsquo;s how to access the database:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;cassert&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">db</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">get_tzdb</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Current DB version: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">db</span><span class="p">.</span><span class="n">version</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">db_list</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">get_tzdb_list</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">size</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">distance</span><span class="p">(</span><span class="n">db_list</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">db_list</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Available versions: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">assert</span><span class="p">(</span><span class="o">&amp;</span><span class="n">db_list</span><span class="p">.</span><span class="n">front</span><span class="p">()</span> <span class="o">==</span> <span class="o">&amp;</span><span class="n">db</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See at <a href="https://godbolt.org/z/Kz8361KGM">Compiler Explorer</a></p> <p>The database provides several key components:</p> <p>Zones (<code>db.zones</code>):</p> <ul> <li>Primary container of time zone information</li> <li>Each zone contains complete historical and current rules</li> <li>Examples: &ldquo;America/New_York&rdquo;, &ldquo;Europe/London&rdquo;</li> </ul> <p>Links (<code>db.links</code>):</p> <ul> <li>Alternative names for existing zones</li> <li>Useful for backward compatibility</li> <li>Example: &ldquo;EST&rdquo; links to &ldquo;America/New_York&rdquo;</li> </ul> <p>Leap Seconds (<code>db.leap_seconds</code>):</p> <ul> <li>Records of historical leap second adjustments</li> <li>Used for precise astronomical calculations</li> </ul> <p>Let&rsquo;s start with a simple approach to explore the zones:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">db</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">get_tzdb</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">now</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">system_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Time Zone Database Version: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">db</span><span class="p">.</span><span class="n">version</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Number of zones: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">db</span><span class="p">.</span><span class="n">zones</span><span class="p">.</span><span class="n">size</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Number of links: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">db</span><span class="p">.</span><span class="n">links</span><span class="p">.</span><span class="n">size</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Number of leap seconds: {}</span><span class="se">\n\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">db</span><span class="p">.</span><span class="n">leap_seconds</span><span class="p">.</span><span class="n">size</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">zone</span> <span class="p">:</span> <span class="n">db</span><span class="p">.</span><span class="n">zones</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">info</span> <span class="o">=</span> <span class="n">zone</span><span class="p">.</span><span class="n">get_info</span><span class="p">(</span><span class="n">now</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{:&lt;30} offset: {:&gt;6}s abbrev: {:&lt;6} &#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">zone</span><span class="p">.</span><span class="n">name</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="n">info</span><span class="p">.</span><span class="n">offset</span><span class="p">.</span><span class="n">count</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="n">info</span><span class="p">.</span><span class="n">abbrev</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Show if DST is active </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">if</span> <span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">save</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">minutes</span><span class="p">{</span><span class="mi">0</span><span class="p">})</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;DST: {} min&#34;</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">save</span><span class="p">.</span><span class="n">count</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Error with zone {}: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">zone</span><span class="p">.</span><span class="n">name</span><span class="p">(),</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See at <a href="https://godbolt.org/z/vrnTe4f3o">Compiler Explorer</a></p> <p>Sample output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Time Zone Database Version: 2024a </span></span><span class="line"><span class="cl">Number of zones: 447 </span></span><span class="line"><span class="cl">Number of links: 150 </span></span><span class="line"><span class="cl">Number of leap seconds: 27 </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">Africa/Abidjan offset: 0s abbrev: GMT </span></span><span class="line"><span class="cl">Africa/Accra offset: 0s abbrev: GMT </span></span><span class="line"><span class="cl">Africa/Addis_Ababa offset: 10800s abbrev: EAT </span></span><span class="line"><span class="cl">... </span></span></code></pre></div><p>While this basic iteration gives us a good overview, the raw offset numbers make it difficult to spot unusual cases. Some zones use fractional hours, and others have unique DST rules. Let&rsquo;s improve our search to find these special cases.</p> <h2 id="finding-unusual-offsets"> Finding Unusual Offsets <a class="hash-link" href="#finding-unusual-offsets" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>What makes a time zone unusual? Usually, it&rsquo;s:</p> <ul> <li>Non-hour offsets (like UTC+5:45)</li> <li>Unusual DST rules (like 30-minute DST changes)</li> </ul> <p>Here&rsquo;s our improved code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;set&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">find_unusual_zones</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">db</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">get_tzdb</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">now</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">system_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Track unique unusual offsets </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">set</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">seconds</span><span class="o">&gt;</span> <span class="n">unusual_offsets</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">zone</span> <span class="p">:</span> <span class="n">db</span><span class="p">.</span><span class="n">zones</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">info</span> <span class="o">=</span> <span class="n">zone</span><span class="p">.</span><span class="n">get_info</span><span class="p">(</span><span class="n">now</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Check if offset is not a whole hour </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">if</span> <span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">offset</span> <span class="o">%</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">hours</span><span class="p">{</span><span class="mi">1</span><span class="p">}</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">seconds</span><span class="p">{</span><span class="mi">0</span><span class="p">})</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">unusual_offsets</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">offset</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Found unusual zone: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">zone</span><span class="p">.</span><span class="n">name</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34; Offset: {:+.2f} hours</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">static_cast</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">offset</span><span class="p">.</span><span class="n">count</span><span class="p">())</span> <span class="o">/</span> <span class="mf">3600.0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34; DST adjustment: {} minutes</span><span class="se">\n\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">info</span><span class="p">.</span><span class="n">save</span><span class="p">.</span><span class="n">count</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Skip problematic zones </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Total unusual offsets found: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">unusual_offsets</span><span class="p">.</span><span class="n">size</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">find_unusual_zones</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/dasW3Y4GY">@Compiler Explorer</a></p> <p>Running this code reveals several interesting time zones:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">Found</span> <span class="n">unusual</span> <span class="nl">zone</span><span class="p">:</span> <span class="n">America</span><span class="o">/</span><span class="n">St_Johns</span> </span></span><span class="line"><span class="cl"> <span class="nl">Offset</span><span class="p">:</span> <span class="o">-</span><span class="mf">3.50</span> <span class="n">hours</span> </span></span><span class="line"><span class="cl"> <span class="n">DST</span> <span class="nl">adjustment</span><span class="p">:</span> <span class="mi">0</span> <span class="n">minutes</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">Found</span> <span class="n">unusual</span> <span class="nl">zone</span><span class="p">:</span> <span class="n">Asia</span><span class="o">/</span><span class="n">Colombo</span> </span></span><span class="line"><span class="cl"> <span class="nl">Offset</span><span class="p">:</span> <span class="o">+</span><span class="mf">5.50</span> <span class="n">hours</span> </span></span><span class="line"><span class="cl"> <span class="n">DST</span> <span class="nl">adjustment</span><span class="p">:</span> <span class="mi">0</span> <span class="n">minutes</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">Found</span> <span class="n">unusual</span> <span class="nl">zone</span><span class="p">:</span> <span class="n">Asia</span><span class="o">/</span><span class="n">Kabul</span> </span></span><span class="line"><span class="cl"> <span class="nl">Offset</span><span class="p">:</span> <span class="o">+</span><span class="mf">4.50</span> <span class="n">hours</span> </span></span><span class="line"><span class="cl"> <span class="n">DST</span> <span class="nl">adjustment</span><span class="p">:</span> <span class="mi">0</span> <span class="n">minutes</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">Found</span> <span class="n">unusual</span> <span class="nl">zone</span><span class="p">:</span> <span class="n">Asia</span><span class="o">/</span><span class="n">Kathmandu</span> </span></span><span class="line"><span class="cl"> <span class="nl">Offset</span><span class="p">:</span> <span class="o">+</span><span class="mf">5.75</span> <span class="n">hours</span> </span></span><span class="line"><span class="cl"> <span class="n">DST</span> <span class="nl">adjustment</span><span class="p">:</span> <span class="mi">0</span> <span class="n">minutes</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="p">...</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="n">Total</span> <span class="n">unusual</span> <span class="n">offsets</span> <span class="nl">found</span><span class="p">:</span> <span class="mi">11</span> </span></span></code></pre></div><h2 id="exploring-unusual-zones"> Exploring Unusual Zones <a class="hash-link" href="#exploring-unusual-zones" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Now let&rsquo;s examine two particularly interesting zones we found using TimeZoneExplorer:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string_view&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">TimeZoneExplorer</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="kt">void</span> <span class="n">explore_zone</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">zone_name</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">zone</span> <span class="o">=</span> <span class="n">locate_zone</span><span class="p">(</span><span class="n">zone_name</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">now</span> <span class="o">=</span> <span class="n">system_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">zoned_time</span> <span class="n">zt</span><span class="p">{</span><span class="n">zone</span><span class="p">,</span> <span class="n">now</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">info</span> <span class="o">=</span> <span class="n">zone</span><span class="o">-&gt;</span><span class="n">get_info</span><span class="p">(</span><span class="n">now</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;</span><span class="se">\n</span><span class="s">=== {} ===</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">zone_name</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Current time: {:%F %T %Z}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">zt</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Valid period: [{}, {})</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">begin</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">end</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;UTC offset: {}s ({:+.2f} hours)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">info</span><span class="p">.</span><span class="n">offset</span><span class="p">.</span><span class="n">count</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="k">static_cast</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">offset</span><span class="p">.</span><span class="n">count</span><span class="p">())</span> <span class="o">/</span> <span class="mf">3600.0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">save</span> <span class="o">==</span> <span class="mi">0</span><span class="n">min</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;DST: No (Standard Time)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;DST: Yes (Saving: {} minutes)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">save</span><span class="p">.</span><span class="n">count</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">standard_offset</span> <span class="o">=</span> <span class="n">info</span><span class="p">.</span><span class="n">offset</span> <span class="o">-</span> <span class="n">info</span><span class="p">.</span><span class="n">save</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Standard Time offset would be: {}s ({:+.2f} hours)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">standard_offset</span><span class="p">.</span><span class="n">count</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="k">static_cast</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">(</span><span class="n">standard_offset</span><span class="p">.</span><span class="n">count</span><span class="p">())</span> <span class="o">/</span> <span class="mf">3600.0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Abbreviation: {} (Note: abbreviations are not unique)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">info</span><span class="p">.</span><span class="n">abbrev</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Error exploring {}: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">zone_name</span><span class="p">,</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">TimeZoneExplorer</span><span class="o">::</span><span class="n">explore_zone</span><span class="p">(</span><span class="s">&#34;Asia/Kathmandu&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">TimeZoneExplorer</span><span class="o">::</span><span class="n">explore_zone</span><span class="p">(</span><span class="s">&#34;Australia/Lord_Howe&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/7z7P91Gbd">@Compiler Explorer</a></p> <p>Output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">=== Asia/Kathmandu === </span></span><span class="line"><span class="cl">Current time: 2024-11-11 02:00:42.203971363 +0545 </span></span><span class="line"><span class="cl">Valid period: [1986-01-01 00:00:00, 32767-12-31 00:00:00) </span></span><span class="line"><span class="cl">UTC offset: 20700s (+5.75 hours) </span></span><span class="line"><span class="cl">DST: No (Standard Time) </span></span><span class="line"><span class="cl">Abbreviation: +0545 (Note: abbreviations are not unique) </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">=== Australia/Lord_Howe === </span></span><span class="line"><span class="cl">Current time: 2024-11-11 07:15:42.209946634 +11 </span></span><span class="line"><span class="cl">Valid period: [2024-10-05 15:30:00, 2025-04-05 15:00:00) </span></span><span class="line"><span class="cl">UTC offset: 39600s (+11.00 hours) </span></span><span class="line"><span class="cl">DST: Yes (Saving: 30 minutes) </span></span><span class="line"><span class="cl">Standard Time offset would be: 37800s (+10.50 hours) </span></span><span class="line"><span class="cl">Abbreviation: +11 (Note: abbreviations are not unique) </span></span></code></pre></div><p>Let&rsquo;s examine these unusual cases:</p> <ol> <li> <p><strong>Nepal (Asia/Kathmandu)</strong>:</p> <ul> <li>Uses UTC+5:45</li> <li>One of the few zones with a 45-minute offset</li> <li>No DST changes</li> <li>Offset hasn&rsquo;t changed since 1986</li> </ul> </li> <li> <p><strong>Lord Howe Island (Australia/Lord_Howe)</strong>:</p> <ul> <li>Base offset is UTC+10:30</li> <li>Uses 30-minute DST adjustment</li> <li>Only place in the world with a 30-minute DST change</li> </ul> </li> </ol> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>C++20&rsquo;s <code>&lt;chrono&gt;</code> library and its time zone support make it easy to explore and work with the world&rsquo;s diverse time zones. While most regions use simple hour offsets from UTC, we discovered several exceptions, like Nepal&rsquo;s UTC+5:45 and Lord Howe Island&rsquo;s unique 30-minute DST adjustment, showing how rich and complex our world&rsquo;s timekeeping really is.</p> What is the current time around the world? Utilizing std::chrono with time zones in C++23 https://www.cppstories.com/2024/chrono_dates_zones/ Sun, 03 Nov 2024 00:00:00 +0000 https://www.cppstories.com/2024/chrono_dates_zones/ <p>In this blog post, we will explore handling dates using <code>std::chrono</code>, including time zones. We&rsquo;ll utilize the latest features of the library to retrieve the current time across various time zones, taking into account daylight saving time changes as well. Additionally, we will incorporate new capabilities introduced in C++23, such as enhanced printing functions and more.</p> <p>Let&rsquo;s start with the following code that prints the current date and time:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">now</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">system_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;now is {}&#34;</span><span class="p">,</span> <span class="n">now</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>You can run it through <a href="https://godbolt.org/z/b65Khse4h">Compiler Explorer</a></p> <p>In my session, I&rsquo;m getting the following results:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Now is 2024-11-01 11:44:06.374573703 </span></span></code></pre></div><p>It&rsquo;s simple, but what time zone are we in? Can we print it in a shorter form? How can we check the time around the world? What about daylight saving time?</p> <p>First things first: time output.</p> <h2 id="improving-the-print"> Improving the print <a class="hash-link" href="#improving-the-print" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>As you can see, I used <code>std::print</code> from C++23, which is available in GCC 14! By default, the time point obtained from <code>::now()</code> is printed with full information, but we can change it and adjust it. For example:</p> <h3 id="basic-date-and-time-formatting"> Basic Date and Time Formatting <a class="hash-link" href="#basic-date-and-time-formatting" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <ul> <li>Show just the date: <code>{0:%F}</code> will format the date as <code>YYYY-MM-DD</code>.</li> <li>Show time in <code>hh:mm:ss</code> format: <code>{0:%T}</code> will format the time as <code>HH:MM:SS</code>.</li> <li>Show the name of the month and/or day of the week: <code>{0:%A, %B}</code> will format it as <code>Day, Month</code>.</li> </ul> <h3 id="advanced-formatting-options"> Advanced Formatting Options <a class="hash-link" href="#advanced-formatting-options" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <ul> <li> <p>Year and Month:</p> <ul> <li><code>{0:%Y}</code>: Full year (e.g., <code>2024</code>).</li> <li><code>{0:%y}</code>: Last two digits of the year (e.g., <code>24</code>).</li> <li><code>{0:%B}</code>: Full month name (e.g., <code>November</code>).</li> <li><code>{0:%b}</code>: Abbreviated month name (e.g., <code>Nov</code>).</li> </ul> </li> <li> <p>Day and Week:</p> <ul> <li><code>{0:%d}</code>: Day of the month, zero-padded (e.g., <code>01</code>).</li> <li><code>{0:%A}</code>: Full weekday name (e.g., <code>Friday</code>).</li> <li><code>{0:%a}</code>: Abbreviated weekday name (e.g., <code>Fri</code>).</li> </ul> </li> <li> <p>Time of Day:</p> <ul> <li><code>{0:%H}</code>: Hour (24-hour clock), zero-padded (e.g., <code>14</code>).</li> <li><code>{0:%I}</code>: Hour (12-hour clock), zero-padded (e.g., <code>02</code>).</li> <li><code>{0:%M}</code>: Minute, zero-padded (e.g., <code>05</code>).</li> <li><code>{0:%S}</code>: Second, zero-padded (e.g., <code>09</code>).</li> <li><code>{0:%p}</code>: AM/PM designation.</li> </ul> </li> <li> <p>Time Zone:</p> <ul> <li><code>{0:%Z}</code>: Time zone abbreviation (e.g., <code>UTC</code>).</li> <li><code>{0:%z}</code>: Offset from UTC (e.g., <code>+0000</code>).</li> </ul> </li> </ul> <p>Here is an example demonstrating some of these formatting options:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">now</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">system_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Full date and time: {0:%Y-%m-%d %H:%M:%S}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">now</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Date only: {0:%F}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">now</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Time only: {0:%T}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">now</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Day of the week: {0:%A}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">now</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Month name: {0:%B}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">now</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;12-hour clock with AM/PM: {0:%I:%M:%S %p}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">now</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;ISO 8601 format: {0:%FT%T%z}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">now</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/bfrsxxfW8">@Compiler Explorer</a></p> <p>Example output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Full date and time: 2024-11-02 19:35:16.296643881 </span></span><span class="line"><span class="cl">Date only: 2024-11-02 </span></span><span class="line"><span class="cl">Time only: 19:35:16.296643881 </span></span><span class="line"><span class="cl">Day of the week: Saturday </span></span><span class="line"><span class="cl">Month name: November </span></span><span class="line"><span class="cl">12-hour clock with AM/PM: 07:35:16.296643881 PM </span></span><span class="line"><span class="cl">ISO 8601 format: 2024-11-02T19:35:16.296643881+0000 </span></span></code></pre></div><p>We can print the time, and it’s now clear that it is always in UTC. What about other time zones?</p> <h2 id="getting-time-in-my-current-time-zone"> Getting time in my current time zone <a class="hash-link" href="#getting-time-in-my-current-time-zone" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>C++20 <code>chrono</code> gives us a powerful module that handles time zones. It&rsquo;s not that easy, as the library has to reach out to the operating system and get the IANA database (see more <a href="https://en.cppreference.com/w/cpp/chrono/tzdb">@std::chrono::tzdb - cppreference.com</a>.</p> <p>But as a user, it&rsquo;s relatively easy for us: we have to use <code>zoned_time</code> and ask for proper <code>time_zone</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">now</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">system_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">zt_local</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">zoned_time</span><span class="p">{</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">current_zone</span><span class="p">(),</span> <span class="n">now</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;now is {} UTC and local is: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">now</span><span class="p">,</span> <span class="n">zt_local</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">try</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">zone</span><span class="p">:</span> <span class="p">{</span><span class="s">&#34;Europe/Warsaw&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="s">&#34;America/New_York&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="s">&#34;Asia/Tokyo&#34;</span> <span class="p">}</span> <span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">zoned_time</span> <span class="n">zt</span><span class="p">{</span><span class="n">zone</span><span class="p">,</span> <span class="n">now</span><span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;{0}: {1:%F} {1:%R}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">zone</span><span class="p">,</span> <span class="n">zt</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">catch</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">runtime_error</span><span class="o">&amp;</span> <span class="n">ex</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Error: {}&#34;</span><span class="p">,</span> <span class="n">ex</span><span class="p">.</span><span class="n">what</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See at <a href="https://godbolt.org/z/7EWG5nTdo">Compiler Explorer</a></p> <p>Example output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">now is 2024-11-12 08:15:22.575519666 UTC and local is: 2024-11-12 08:15:22.575519666 </span></span><span class="line"><span class="cl">Europe/Warsaw: 2024-11-12 09:15 </span></span><span class="line"><span class="cl">America/New_York: 2024-11-12 03:15 </span></span><span class="line"><span class="cl">Asia/Tokyo: 2024-11-12 17:15 </span></span></code></pre></div><p>Compiler Explorer apparently runs on some servers located in the UTC time zone, so there&rsquo;s no difference in time. But my time zone - Warsaw/Poland - shows different times, Similar to New York and Tokyo.</p> <p>Let&rsquo;s now dive into the details:</p> <ol> <li>Getting the Current Time: <ul> <li>We start by obtaining the current time using <code>std::chrono::system_clock::now()</code>. This gives us the current time in UTC.</li> </ul> </li> <li>Local Time Zone: <ul> <li>We create a <code>std::chrono::zoned_time</code> object using <code>std::chrono::current_zone()</code>, which automatically detects the local time zone of the system where the code is running. This allows us to convert the UTC time to the local time zone.</li> </ul> </li> <li>Time Zone Conversion: - We define three time zones using <code>std::string_view</code>: Warsaw, New York, and Tokyo. These are specified using their respective IANA time zone identifiers. <ul> <li>For each time zone, we create a <code>std::chrono::zoned_time</code> object, which converts the current UTC time to the specified time zone.</li> </ul> </li> <li>Printing the Results: <ul> <li>We use <code>std::print</code> to display the current time in UTC and the local time zone.</li> <li>For each specified time zone (Warsaw, New York, Tokyo), we print the date and time using the format specifiers <code>{0:%F}</code> for the date (<code>YYYY-MM-DD</code>) and <code>{0:%R}</code> for the time (<code>HH:MM</code>).</li> </ul> </li> <li>Error Handling: <ul> <li>The code is wrapped in a <code>try-catch</code> block to handle any potential runtime errors, such as invalid time zone identifiers.</li> </ul> </li> </ol> <h2 id="daylight-saving-time"> Daylight saving time <a class="hash-link" href="#daylight-saving-time" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>We can even check some extra information related to our current time zone. We can obtain <code>info</code> from our <code>zoned_time</code> and print information like start/end, offset, and more:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">now</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">floor</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">minutes</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">system_clock</span><span class="o">::</span><span class="n">now</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">zt_local</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">zoned_time</span><span class="p">{</span> <span class="s">&#34;Europe/Warsaw&#34;</span><span class="p">,</span> <span class="n">now</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;now is {} UTC and Warsaw is: {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">now</span><span class="p">,</span> <span class="n">zt_local</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">info</span> <span class="o">=</span> <span class="n">zt_local</span><span class="p">.</span><span class="n">get_info</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;local time info: </span><span class="se">\n</span><span class="s">abbrev: {},</span><span class="se">\n</span><span class="s"> begin {}, end {}, </span><span class="se">\n</span><span class="s">offset {}, save {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">info</span><span class="p">.</span><span class="n">abbrev</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">begin</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">end</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">offset</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">save</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">catch</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">runtime_error</span><span class="o">&amp;</span> <span class="n">ex</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Error: {}&#34;</span><span class="p">,</span> <span class="n">ex</span><span class="p">.</span><span class="n">what</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See <a href="https://godbolt.org/z/MbWTKd3aq">@Compiler Explorer</a></p> <p>and daylight info:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;print&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">printInfo</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">sys_days</span> <span class="n">sd</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">zone</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">zt_local</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">zoned_time</span><span class="p">{</span> <span class="s">&#34;Europe/Warsaw&#34;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">sys_days</span><span class="p">{</span><span class="n">sd</span><span class="p">}</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">info</span> <span class="o">=</span> <span class="n">zt_local</span><span class="p">.</span><span class="n">get_info</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;time info for {:%F} in {}:</span><span class="se">\n</span><span class="s">abbrev: {},</span><span class="se">\n</span><span class="s">begin {}, end {}, </span><span class="se">\n</span><span class="s">offset {}, save {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">sd</span><span class="p">,</span> <span class="n">zone</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">abbrev</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">begin</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">end</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">offset</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">save</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">printInfo</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="p">{</span> <span class="mi">2024</span> <span class="p">}</span> <span class="o">/</span> <span class="mi">9</span> <span class="o">/</span> <span class="mi">14</span><span class="p">,</span> <span class="s">&#34;Europe/Warsaw&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">printInfo</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">year</span><span class="p">{</span> <span class="mi">2024</span> <span class="p">}</span> <span class="o">/</span> <span class="mi">11</span> <span class="o">/</span> <span class="mi">14</span><span class="p">,</span> <span class="s">&#34;Europe/Warsaw&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">catch</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">runtime_error</span><span class="o">&amp;</span> <span class="n">ex</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&#34;Error: {}&#34;</span><span class="p">,</span> <span class="n">ex</span><span class="p">.</span><span class="n">what</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/7e7aYEKhf">@Compiler Explorer</a></p> <p>I&rsquo;m getting:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">time info for 2024-09-14 in Europe/Warsaw: </span></span><span class="line"><span class="cl">abbrev: CEST, </span></span><span class="line"><span class="cl">begin 2024-03-31 01:00:00, end 2024-10-27 01:00:00, </span></span><span class="line"><span class="cl">offset 7200s, save 60min </span></span><span class="line"><span class="cl">time info for 2024-11-14 in Europe/Warsaw: </span></span><span class="line"><span class="cl">abbrev: CET, </span></span><span class="line"><span class="cl">begin 2024-10-27 01:00:00, end 2025-03-30 01:00:00, </span></span><span class="line"><span class="cl">offset 3600s, save 0min </span></span></code></pre></div><p>As you can see, we get the following information:</p> <ul> <li><code>info.abbrev</code> - zone abbreviation name, like CET, PT, etc</li> <li><code>info.begin</code>, <code>info.end</code> - start and end date (in <code>sys_seconds</code>) for a given time zone, usually changes when there&rsquo;s a daylight time zone switch</li> <li><code>info.offset</code> - offset from UTC time</li> <li><code>info.save</code> - if nonzero, indicates that the time zone is on daylight saving time</li> </ul> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>What a ride! We began with a simple display of the current time and progressed to more complex scenarios, including various formatting options available in C++20 and C++23, as well as time zones. In the end, we explored how to check details of a specific timepoint and examine the information related to its time zone.</p> <div class="bonusWrapper"> <div class="bonusInfo"> <p> Would you like to <strong>see more?</strong> <br /> Read my other articles on <code>std::chrono</code>. See <a href="https://www.patreon.com/posts/71964550" target="_blank">Exploring std::chrono in C++20 - Time Zones </a> or <a href="https://www.patreon.com/posts/67821031" target="_blank">Exploring std::chrono in C++20 - Calendar Types ~2700 words</a>, which are available for <i>C++ Stories Premium/Patreon</i> members. See all <a href="https://www.cppstories.com/p/extra-patreon-content/">Premium benefits here</a>. </p> </div> </div> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Have you tried std::chrono?</li> <li>Do you use the latest additions from C++20 for date support?</li> </ul> <p>Share your comments below.</p> C++ String Conversion: Exploring std::from_chars in C++17 to C++26 https://www.cppstories.com/2018/12/fromchars/ Sun, 13 Oct 2024 00:00:00 +0000 https://www.cppstories.com/2018/12/fromchars/ <p>With the introduction of C++17, the C++ Standard Library expanded its capabilities for converting text to numbers with the addition of <code>std::from_chars</code>. This low-level, high-performance API offers significant advantages over previous methods, such as <code>atoi</code> and <code>stringstream</code>. In this article, we will explore the evolution of string conversion routines from C++17 through C++26, highlighting key improvements like <code>constexpr</code> support and enhanced error handling. Let&rsquo;s dive into the details and see how <code>std::from_chars</code> can transform your approach to string conversion.</p> <p><strong>Updated in Oct 2024:</strong> Added notes from <code>constexpr</code> support in C++23, and C++26 improvements, plus more Compiler Explorer examples.</p> <h2 id="before-c17"> Before C++17 <a class="hash-link" href="#before-c17" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>C++, before C++17, offered several options when it comes to string conversion:</p> <ul> <li><code>sprintf</code> / <code>snprintf</code></li> <li><code>sscanf</code></li> <li><code>atol</code></li> <li><code>strtol</code></li> <li><code>strstream</code></li> <li><code>stringstream</code></li> <li><code>to_string</code></li> <li><code>stoi</code> and similar functions</li> </ul> <p>And with C++17 you get another option: <code>std::from_chars</code>! Wasn’t the old stuff good enough? Why do we need new methods?</p> <p>In short: because <code>from_chars</code> is low-level, and offers the best possible performance.</p> <p>The new conversion routines are:</p> <ul> <li>non-throwing</li> <li>non-allocating</li> <li>no locale support</li> <li>memory safety</li> <li>error reporting gives additional information about the conversion outcome</li> </ul> <p>The API might not be the most friendly to use, but it’s easy enough to wrap it into some facade.</p> <p>A simple example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">str</span> <span class="p">{</span> <span class="s">&#34;12345678901234&#34;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">from_chars</span><span class="p">(</span><span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span><span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">()</span> <span class="o">+</span> <span class="n">str</span><span class="p">.</span><span class="n">size</span><span class="p">(),</span> <span class="n">value</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="c1">// error checking ommited... </span></span></span></code></pre></div><h2 id="the-series"> The Series <a class="hash-link" href="#the-series" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>This article is part of my series about C++17 Library Utilities. Here’s the list of the topics in the series:</p> <ul> <li><a href="https://www.cppstories.com/2018/04/refactoring-with-c17-stdoptional.html">Refactoring with <code>std::optional</code></a></li> <li><a href="https://www.cppstories.com/2018/05/using-optional.html">Using <code>std::optional</code></a></li> <li><a href="https://www.cppstories.com/2018/05/errors-and-optional.html">Error handling and <code>std::optional</code></a></li> <li><a href="https://www.cppstories.com/2018/06/variant.html">Everything You Need to Know About <code>std::variant</code> from C++17</a></li> <li><a href="https://www.cppstories.com/2018/06/any.html">Everything You Need to Know About <code>std::any</code> from C++17</a></li> <li><a href="https://www.cppstories.com/2018/07/string-view-perf.html"><code>std::string_view</code> Performance</a> and <a href="https://www.cppstories.com/2018/07/string-view-perf-followup.html">followup</a></li> <li><a href="https://www.cppstories.com/2018/08/searchers.html">C++17 string searchers</a> and <a href="https://www.cppstories.com/2018/08/searcher-preprocessing.html">followup</a></li> <li>Conversion utilities: <a href="https://www.cppstories.com/2018/12/fromchars/">on <code>std::from_chars</code> - from a string to a number</a> and <a href="https://www.cppstories.com/2019/11/tochars/">on <code>std::to_chars</code> - from numbers into strings</a></li> <li><a href="https://www.cppstories.com/2019/01/filesize.html">How to get File Size in C++?</a> and <a href="https://www.cppstories.com/2019/01/filesizeadvantages.html">std:filesystem::file_size Advantages and Differences</a></li> <li><a href="https://www.cppstories.com/2019/04/dir-iterate.html">How To Iterate Through Directories</a></li> </ul> <p><a href="https://leanpub.com/cpp17indetail?utm_source=blog&amp;utm_campaign=stdcpp17series"><img src="../../images/cpp17indetail.png" alt=""></a></p> <p>Resources about C++17 STL:</p> <ul> <li><a href="https://leanpub.com/cpp17indetail?utm_source=blog&amp;utm_campaign=stdcpp17series"><strong>C++17 In Detail</strong></a> by Bartek!</li> <li><a href="https://leanpub.com/cpp17">C++17 - The Complete Guide</a> by Nicolai Josuttis</li> <li><a href="https://pluralsight.pxf.io/c/1192940/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fcplusplus-fundamentals-c17">C++ Fundamentals Including C++ 17</a> by Kate Gregory</li> <li><a href="https://pluralsight.pxf.io/c/1192940/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fcplusplus-14-practical-features">Practical C++14 and C++17 Features</a> - by Giovanni Dicanio</li> <li><a href="http://amzn.to/2v6KkmV">C++17 STL Cookbook</a> by Jacek Galowicz</li> </ul> <p>Let’s have a look at the API now.</p> <h2 id="converting-from-characters-to-numbers-from_chars"> Converting From Characters to Numbers: <code>from_chars</code> <a class="hash-link" href="#converting-from-characters-to-numbers-from_chars" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p><code>std::from_chars</code>, available in the <code>&lt;charconv&gt;</code> headers, is a set of overloaded functions: for integral types and floating point types.</p> <p>For integral types we have the following functions:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">from_chars_result</span> <span class="n">from_chars</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">first</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">last</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">TYPE</span> <span class="o">&amp;</span><span class="n">value</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">base</span> <span class="o">=</span> <span class="mi">10</span><span class="p">);</span> </span></span></code></pre></div><p>Where <code>TYPE</code> expands to all available signed and unsigned integer types and <code>char</code>.</p> <p><code>base</code> can be a number ranging from 2 to 36.</p> <p>Then there’s the floating point version:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">from_chars_result</span> <span class="n">from_chars</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">first</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">last</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">FLOAT_TYPE</span><span class="o">&amp;</span> <span class="n">value</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">chars_format</span> <span class="n">fmt</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chars_format</span><span class="o">::</span><span class="n">general</span><span class="p">);</span> </span></span></code></pre></div><p><code>FLOAT_TYPE</code> expands to <code>float</code>, <code>double</code> or <code>long double</code>.</p> <p><code>chars_format</code> is an enum with the following values: <code>scientific</code>,</p> <p><code>fixed</code>, <code>hex</code> and <code>general</code> (which is a composition of <code>fixed</code> and <code>scientific</code>).</p> <p>The return value in all of those functions (for integers and floats) is <code>from_chars_result</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">from_chars_result</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">ptr</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">errc</span> <span class="n">ec</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span></code></pre></div><p><code>from_chars_result</code> holds valuable information about the conversion process.</p> <p>Here’s the summary:</p> <table> <thead> <tr class="header"> <th>Return Condition</th> <th>State of <code>from_chars_result</code></th> </tr> </thead> <tbody> <tr class="odd"> <td>Success</td> <td><code>ptr</code> points at the first character not matching the pattern, or has the value equal to <code>last</code> if all characters match and <code>ec</code> is value-initialized.</td> </tr> <tr class="even"> <td>Invalid conversion</td> <td><code>ptr</code> equals <code>first</code> and <code>ec</code> equals <code>std::errc::invalid_argument</code>. <code>value</code> is unmodified.</td> </tr> <tr class="odd"> <td>Out of range</td> <td>The number it too large to fit into the value type. <code>ec</code> equals <code>std::errc::result_out_of_range</code> and <code>ptr</code> points at the first character not matching the pattern. <code>value</code> is unmodified.</td> </tr> </tbody> </table> <p>The new routines are very low level, so you might be wondering why is that. Titus Winters added <a href="http://disq.us/p/1xy9sse">a great summary in comments</a>:</p> <blockquote> <p>The intent of those APIs is *not* for people to use them directly, but to build more interesting/useful things on top of them. These are primitives, and we (the committee) believe they have to be in the standard because there isn&rsquo;t an efficient way to do these operations without calling back out to nul-terminated C routines</p> </blockquote> <h2 id="examples"> Examples <a class="hash-link" href="#examples" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Here are two examples of how to convert a string into a number using <code>from_chars</code>, to <code>int</code> and<code>float</code>.</p> <h3 id="integral-types"> Integral types <a class="hash-link" href="#integral-types" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;charconv&gt; // from_char, to_char</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">str</span> <span class="p">{</span> <span class="s">&#34;12345678901234&#34;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">res</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">from_chars</span><span class="p">(</span><span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">()</span> <span class="o">+</span> <span class="n">str</span><span class="p">.</span><span class="n">size</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="n">value</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;value: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">value</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="s">&#34;, distance: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">res</span><span class="p">.</span><span class="n">ptr</span> <span class="o">-</span> <span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="o">::</span><span class="n">invalid_argument</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;invalid argument!</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="o">::</span><span class="n">result_out_of_range</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;out of range! res.ptr distance: &#34;</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="n">res</span><span class="p">.</span><span class="n">ptr</span> <span class="o">-</span> <span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>The example is straightforward, it passes a string <code>str</code> into <code>from_chars</code> and then displays the result with additional information if possible.</p> <p>your task is to run the code <a href="https://godbolt.org/z/5bxe8jx3E">@Compiler Explorer</a>.</p> <p>Does &ldquo;12345678901234&rdquo; fit into the number? Or you see some errors from the conversion API?</p> <h3 id="floating-point"> Floating Point <a class="hash-link" href="#floating-point" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Here&rsquo;s the floating pointer version:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;charconv&gt; // from_char, to_char</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">str</span> <span class="p">{</span> <span class="s">&#34;16.78&#34;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="kt">double</span> <span class="n">value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">format</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chars_format</span><span class="o">::</span><span class="n">general</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">res</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">from_chars</span><span class="p">(</span><span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">()</span> <span class="o">+</span> <span class="n">str</span><span class="p">.</span><span class="n">size</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="n">value</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">format</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;value: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">value</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="s">&#34;, distance: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">res</span><span class="p">.</span><span class="n">ptr</span> <span class="o">-</span> <span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="o">::</span><span class="n">invalid_argument</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;invalid argument!</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="o">::</span><span class="n">result_out_of_range</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;out of range! res.ptr distance: &#34;</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="n">res</span><span class="p">.</span><span class="n">ptr</span> <span class="o">-</span> <span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run at <a href="https://godbolt.org/z/66nbshE74">Compiler Explorer</a></p> <p>Here’s the example output that we can get:</p> <table> <thead> <tr class="header"> <th><code>str</code> value</th> <th><code>format</code> value</th> <th>output</th> </tr> </thead> <tbody> <tr class="odd"> <td><code>1.01</code></td> <td><code>fixed</code></td> <td><code>value: 1.01, distance 4</code></td> </tr> <tr class="even"> <td><code>-67.90000</code></td> <td><code>fixed</code></td> <td><code>value: -67.9, distance: 9</code></td> </tr> <tr class="odd"> <td><code>20.9</code></td> <td><code>scientific</code></td> <td><code>invalid argument!, res.ptr distance: 0</code></td> </tr> <tr class="even"> <td><code>20.9e+0</code></td> <td><code>scientific</code></td> <td><code>value: 20.9, distance: 7</code></td> </tr> <tr class="odd"> <td><code>-20.9e+1</code></td> <td><code>scientific</code></td> <td><code>value: -209, distance: 8</code></td> </tr> <tr class="even"> <td><code>F.F</code></td> <td><code>hex</code></td> <td><code>value: 15.9375, distance: 3</code></td> </tr> <tr class="odd"> <td><code>-10.1</code></td> <td><code>hex</code></td> <td><code>value: -16.0625, distance: 5</code></td> </tr> </tbody> </table> <p>The <code>general</code> format is a combination of <code>fixed</code> and <code>scientific</code> so it handles regular floating point string with the additional support for <code>e+num</code> syntax.</p> <h2 id="performance"> Performance <a class="hash-link" href="#performance" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>I did some benchmarks, and the new routines are blazing fast!</p> <p>Some numbers:</p> <ul> <li>On GCC it’s around 4.5x faster than <code>stoi</code>, 2.2x faster than <code>atoi</code> and almost 50x faster than <code>istringstream</code>.</li> <li>On Clang it’s around 3.5x faster than <code>stoi</code>, 2.7x faster than <code>atoi</code> and 60x faster than <code>istringstream</code>!</li> <li>MSVC performs around 3x faster than <code>stoi</code>, ~2x faster than <code>atoi</code> and almost 50x faster than <code>istringstream</code></li> </ul> <p>You can find the results in my book on C++17: <a href="https://leanpub.com/cpp17indetail?utm_source=blog&amp;utm_campaign=stdcpp17series"><strong>C++17 In Detail</strong></a>.</p> <h2 id="c23-updates"> C++23 Updates <a class="hash-link" href="#c23-updates" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In C++23 we got one improvement for our functions: <a href="https://wg21.link/P2291R3">P2291</a></p> <blockquote> <p><code>constexpr</code> for integral overloads of <code>std::to_chars()</code> and <code>std::from_chars()</code>.</p> </blockquote> <p>It&rsquo;s already implemented in GCC 13, Clang 16, and MSVC 19.34.</p> <p>Together with <code>std::optional</code> that can also work in the <code>constexpr</code> context we can create the following example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;charconv&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;optional&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string_view&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">to_int</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">sv</span><span class="p">)</span> </span></span><span class="line"><span class="cl"><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">value</span> <span class="p">{};</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">from_chars</span><span class="p">(</span><span class="n">sv</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">sv</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">value</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">ret</span><span class="p">.</span><span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="p">{})</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">value</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{};</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">to_int</span><span class="p">(</span><span class="s">&#34;hello&#34;</span><span class="p">)</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">nullopt</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="k">static_assert</span><span class="p">(</span><span class="n">to_int</span><span class="p">(</span><span class="s">&#34;10&#34;</span><span class="p">)</span> <span class="o">==</span> <span class="mi">10</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/aTPe9T7oE">@Compiler Explorer</a></p> <h2 id="c26-updates"> C++26 Updates <a class="hash-link" href="#c26-updates" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The work is not complete, and looks like in C++26 we&rsquo;ll have more additions:</p> <p>See <a href="https://wg21.link/P2497R0">P2497R0</a> wchich is already accepted into the working draft of C++26:</p> <blockquote> <p>Testing for success or failure of <code>&lt;charconv&gt;</code> functions</p> </blockquote> <p>The feature is already implemented in GCC 14 and Clang 18.</p> <p>In short <code>from_chars_result</code> (as well as <code>to_chars_result</code>) gets a <code>bool</code> conversion operator:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="k">explicit</span> <span class="k">operator</span> <span class="nf">bool</span><span class="p">()</span> <span class="k">const</span> <span class="k">noexcept</span><span class="p">;</span> </span></span></code></pre></div><p>And it has to return <code>ec == std::errc{}</code>.</p> <p>This means our code can be a bit simpler:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">ec</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="p">())</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span> </span></span></code></pre></div><p>can become:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">res</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span> </span></span></code></pre></div><p>For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// ... </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="k">auto</span> <span class="n">res</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">from_chars</span><span class="p">(</span><span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">()</span> <span class="o">+</span> <span class="n">str</span><span class="p">.</span><span class="n">size</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="n">value</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">format</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">res</span><span class="p">)</span> </span></span><span class="line"><span class="cl"><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;value: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">value</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="s">&#34;, distance: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">res</span><span class="p">.</span><span class="n">ptr</span> <span class="o">-</span> <span class="n">str</span><span class="p">.</span><span class="n">data</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="c1">// ... </span></span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/WE8T7anET">@Compiler Explorer</a></p> <h2 id="compiler-support-for-stdfrom_chars-in-c"> Compiler Support for <code>std::from_chars</code> in C++ <a class="hash-link" href="#compiler-support-for-stdfrom_chars-in-c" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <ul> <li> <p><strong>Visual Studio:</strong> Full support for <code>std::from_chars</code> was introduced in Visual Studio 2019 version 16.4, with floating-point support starting from VS 2017 version 15.7. Visual Studio 2022 includes C++23 features like <code>constexpr</code> for integral overloads.</p> </li> <li> <p><strong>GCC:</strong> Starting with GCC 11.0, <code>std::from_chars</code> offers full support, including integer and floating-point conversions. The latest GCC versions, such as GCC 13, incorporate <code>constexpr</code> integral support.</p> </li> <li> <p><strong>Clang:</strong> Clang 7.0 introduced initial support for integer conversions. Clang 16 and above support <code>constexpr</code> for integral overloads.</p> </li> </ul> <p>For the most accurate and up-to-date information see <a href="https://en.cppreference.com/w/cpp/compiler_support/17">CppReference, Compiler Support</a>.</p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>If you want to convert text into a number and you don’t need any extra stuff like locale support then <code>std::from_chars</code> might be the best choice. It offers great performance, and what’s more, you’ll get a lot of information about the conversion process (for example how much characters were scanned).</p> <p>The routines might be especially handy with parsing JSON files, 3d textual model representation (like OBJ file formats), etc.</p> <p>What&rsquo;s more the new functions can be evan used at compile-time (as of C++23), and have even better error checking in C++26.</p> <h3 id="references"> References <a class="hash-link" href="#references" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>If you want to read more about existing conversion routines, new ones and also see some benchmarks you can see two great posts at @fluentcpp:</p> <ul> <li><a href="https://www.fluentcpp.com/2018/07/24/how-to-convert-a-string-to-an-int-in-c/">How to Convert a String to an int in C++</a> and</li> <li><a href="https://www.fluentcpp.com/2018/07/27/how-to-efficiently-convert-a-string-to-an-int-in-c/">How to *Efficiently* Convert a String to an int in C++</a> written by JFT.</li> <li><a href="https://lemire.me/blog/2022/07/27/comparing-strtod-with-from_chars-gcc-12/">Comparing strtod with <code>from_chars</code> (GCC 12) – Daniel Lemire&rsquo;s blog</a></li> </ul> <h4 id="your-turn"> Your Turn </h4> <ul> <li>Have you played with the new conversion routines?</li> <li>What do you usually use to convert text into numbers?</li> </ul> std::initializer_list in C++ 2/2 - Caveats and Improvements https://www.cppstories.com/2023/initializer_list_improvements/ Sun, 29 Sep 2024 00:00:00 +0000 https://www.cppstories.com/2023/initializer_list_improvements/ <p>In this article, you&rsquo;ll learn why <code>std::initializer_list</code> has a bad reputation in C++. Is passing values using it as efficient as &ldquo;emplace&rdquo;? How can we use non-copyable types? You&rsquo;ll also see how to fix some of the problems.</p> <p>Let&rsquo;s start with the issues first:</p> <p><strong>Updated in Sept 2024:</strong> Added note about stack overflow and C++26 fixes.</p> <blockquote class="hint note"> This is the second part of <code>initalizer_list</code> mini-series. See the first part on <a href="https://www.cppstories.com/2023/initializer_list_basics/">Basics and use cases here</a>. </blockquote> <h2 id="1-referencing-local-array"> 1. Referencing local array <a class="hash-link" href="#1-referencing-local-array" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>If you recall from the previous article, <code>std::initializer_list</code> expands to some unnamed local array of const objects. So the following code might be super unsafe:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">wrong</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// for illustration only! </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">return</span> <span class="p">{</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">wrong</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>The above code is equivalent to the following:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">wrong</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">int</span> <span class="n">arr</span><span class="p">[]</span> <span class="p">{</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">{</span><span class="n">arr</span><span class="p">,</span> <span class="n">arr</span><span class="o">+</span><span class="mi">4</span><span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">initializer_list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">x</span> <span class="o">=</span> <span class="n">wrong</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>The example serves to highlight the error, emphasizing the importance of avoiding similar mistakes in our own code. The function returns pointers/iterators to a local object, and that will cause undefined behavior. See a demo <a href="https://godbolt.org/z/bonveWf4a">@Compiler Explorer</a>.</p> <p>GCC or Clang reports a handy warning in this case:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">GCC: </span></span><span class="line"><span class="cl">warning: returning temporary &#39;initializer_list&#39; does not extend the lifetime of the underlying array [-Winit-list-lifetime] </span></span><span class="line"><span class="cl"> 5 | return { 1, 2, 3, 4}; </span></span></code></pre></div><p>Or in Clang:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&lt;source&gt;:5:12: warning: returning address of local temporary object [-Wreturn-stack-address] </span></span><span class="line"><span class="cl"> return { 1, 2, 3, 4}; </span></span></code></pre></div><p>We can make the following conclusion:</p> <blockquote> <p><code>std::initializer_list</code> is a &ldquo;view&rdquo; type; it references some implementation-dependent and a local array of <code>const</code> values. Use it mainly for passing into functions when you need a variable number of arguments of the same type. If you try to return such lists and pass them around, then you risk lifetime issues. Use with care.</p> </blockquote> <p>Let&rsquo;s take on another limitation:</p> <h2 id="2-the-cost-of-copying-elements"> 2. The cost of copying elements <a class="hash-link" href="#2-the-cost-of-copying-elements" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Passing elements through <code>std::initializer_list</code> is very convenient, but it&rsquo;s good to know that when you pass it to a <code>std::vector</code>&rsquo;s constructor (or other standard containers), each element has to be copied. It&rsquo;s because, conceptually, objects in the <code>initializer_list</code> are put into a <code>const</code> temporary array, so they have to be copied to the container.</p> <p>Let&rsquo;s compare the following case:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;vec... { }</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Object</span><span class="o">&gt;</span> <span class="n">vec</span> <span class="p">{</span> <span class="n">Object</span><span class="p">(</span><span class="s">&#34;John&#34;</span><span class="p">),</span> <span class="n">Object</span><span class="p">(</span><span class="s">&#34;Doe&#34;</span><span class="p">),</span> <span class="n">Object</span><span class="p">(</span><span class="s">&#34;Jane&#34;</span><span class="p">)</span> <span class="p">};</span> </span></span></code></pre></div><p>With:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;vec emplace{}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Object</span><span class="o">&gt;</span> <span class="n">vec</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">vec</span><span class="p">.</span><span class="n">reserve</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">vec</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="s">&#34;John&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">vec</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="s">&#34;Doe&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">vec</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="s">&#34;Jane&#34;</span><span class="p">);</span> </span></span></code></pre></div><p>The <code>Object</code> class is a simple wrapper around <code>std::string</code> with some extra logging code. You can run the example <a href="https://godbolt.org/z/c3Prf6619">@Compiler Explorer</a>.</p> <p>And we&rsquo;ll get:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">vec... { } </span></span><span class="line"><span class="cl">MyType::MyType John </span></span><span class="line"><span class="cl">MyType::MyType Doe </span></span><span class="line"><span class="cl">MyType::MyType Jane </span></span><span class="line"><span class="cl">MyType::MyType(const MyType&amp;) John </span></span><span class="line"><span class="cl">MyType::MyType(const MyType&amp;) Doe </span></span><span class="line"><span class="cl">MyType::MyType(const MyType&amp;) Jane </span></span><span class="line"><span class="cl">MyType::~MyType Jane </span></span><span class="line"><span class="cl">MyType::~MyType Doe </span></span><span class="line"><span class="cl">MyType::~MyType John </span></span><span class="line"><span class="cl">MyType::~MyType John </span></span><span class="line"><span class="cl">MyType::~MyType Doe </span></span><span class="line"><span class="cl">MyType::~MyType Jane </span></span><span class="line"><span class="cl">vec emplace{} </span></span><span class="line"><span class="cl">MyType::MyType John </span></span><span class="line"><span class="cl">MyType::MyType Doe </span></span><span class="line"><span class="cl">MyType::MyType Jane </span></span><span class="line"><span class="cl">MyType::~MyType John </span></span><span class="line"><span class="cl">MyType::~MyType Doe </span></span><span class="line"><span class="cl">MyType::~MyType Jane </span></span></code></pre></div><p>As you can see, something is wrong! In the case of the single constructor, we can spot some extra temporary objects! On the other hand, the case with <code>emplace_back()</code> has no temporaries.</p> <p>We can link this issue with the following element:</p> <h2 id="3-non-copyable-types"> 3. Non-copyable types <a class="hash-link" href="#3-non-copyable-types" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The extra copy that we&rsquo;d get with the <code>initializer_list</code>, also causes issues when your objects are not copyable. For example, when you want to create a vector of <code>unique_ptr</code>.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;memory&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Shape</span> <span class="p">{</span> <span class="k">virtual</span> <span class="kt">void</span> <span class="nf">render</span><span class="p">()</span> <span class="k">const</span> <span class="p">;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Circle</span> <span class="o">:</span> <span class="n">Shape</span> <span class="p">{</span> <span class="kt">void</span> <span class="nf">render</span><span class="p">()</span> <span class="k">const</span> <span class="k">override</span><span class="p">;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Rectangle</span> <span class="o">:</span> <span class="n">Shape</span> <span class="p">{</span> <span class="kt">void</span> <span class="nf">render</span><span class="p">()</span> <span class="k">const</span> <span class="k">override</span><span class="p">;</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o">&lt;</span><span class="n">Shape</span><span class="o">&gt;&gt;</span> <span class="n">shapes</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="n">Circle</span><span class="o">&gt;</span><span class="p">(),</span> <span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="n">Rectangle</span><span class="o">&gt;</span><span class="p">()</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/xPoxxr1ba">@Compiler Explorer</a></p> <p>The line where I want to create a vector fails to compile, and we get many messages about copying issues.</p> <p>In short: the unique pointers cannot be copied. They can only be moved, and passing <code>initializer_list</code> doesn&rsquo;t give us any options to handle those cases. The only way to build such a container is to use <code>emplace_back</code> or <code>push_back</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o">&lt;</span><span class="n">Shape</span><span class="o">&gt;&gt;</span> <span class="n">shapes</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">shapes</span><span class="p">.</span><span class="n">reserve</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">shapes</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="n">Circle</span><span class="o">&gt;</span><span class="p">());</span> <span class="c1">// or </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">shapes</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="n">Rectangle</span><span class="o">&gt;</span><span class="p">());</span> </span></span></code></pre></div><p>See the working code at <a href="https://godbolt.org/z/E7h4vzYP4">Compiler Explorer</a>.</p> <h2 id="4-stack-space-and-large-lists-fixed-in-c26"> 4. Stack space and large lists (fixed in C++26) <a class="hash-link" href="#4-stack-space-and-large-lists-fixed-in-c26" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Remember that each initializer list requires a const array of objects&hellip; consider this code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="nf">getImageBytes</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">byte</span><span class="o">&gt;</span> <span class="n">v</span> <span class="o">=</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="mh">0xff</span><span class="p">,</span> <span class="mh">0xaa</span><span class="p">,</span> <span class="mh">0xce</span><span class="p">,</span> <span class="p">...</span> <span class="c1">// 2MB of soma image data </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>At first glance, this code is safe, all it does is it allocates dynamic memory and puts the content of the file into that memory block.</p> <p>But&hellip;</p> <p>Because we have this backing array, we end up with the following code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="nf">getImageBytes</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">byte</span> <span class="n">bytes</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="mh">0xff</span><span class="p">,</span> <span class="mh">0xaa</span><span class="p">,</span> <span class="mh">0xce</span><span class="p">,</span> <span class="p">...</span> <span class="c1">// 2MB of soma image data </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">byte</span><span class="o">&gt;</span> <span class="n">v</span><span class="p">(</span><span class="n">bytes</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">bytes</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">v</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>This temp array is allocated on the stack. For large arrays (like our 2MB of data), this can exceed the stack size limit and cause a stack overflow, crashing your application.</p> <p>You can fix this code as of C++23 by using your custom backing array:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">auto</span> <span class="nf">getImageBytes</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">byte</span> <span class="n">bytes</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="mh">0xff</span><span class="p">,</span> <span class="mh">0xaa</span><span class="p">,</span> <span class="mh">0xce</span><span class="p">,</span> <span class="p">...</span> <span class="c1">// 2MB of soma image data </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">byte</span><span class="o">&gt;</span><span class="p">(</span><span class="n">bytes</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">bytes</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Now, we have control over the array and we can put it into a static storage and thus it won&rsquo;t use stack space.</p> <p>Fortunately, starting from C++26, thanks to P2752R3 &ldquo;Static storage for braced initializers&rdquo;, the compiler will handle this situation more gracefully.</p> <p>The proposal allows compilers to place the temporary array backing an initializer list into static storage automatically when the array is large. This means that large initializer lists won&rsquo;t cause stack overflows, and you won&rsquo;t need to manually declare arrays as static.</p> <p>For more details, you can read Arthur O&rsquo;Dwyer&rsquo;s explanation on #embed and the static storage proposal: <a href="https://quuxplusone.github.io/blog/2023/01/13/embed-and-initializer-lists/">P1967 `#embed` and D2752 &ldquo;Static storage for `initializer_list`&rdquo; are now on Compiler Explorer – Arthur O&rsquo;Dwyer – Stuff mostly about C++</a>.</p> <h2 id="alternative-variadic-function"> Alternative: variadic function <a class="hash-link" href="#alternative-variadic-function" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>If you want to reduce the number of temporary objects, or your types are not copyable, then you can use the following factory function for <code>std::vector</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="k">typename</span><span class="p">...</span> <span class="n">Args</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">initHelper</span><span class="p">(</span><span class="n">Args</span><span class="o">&amp;&amp;</span><span class="p">...</span> <span class="n">args</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">vec</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">vec</span><span class="p">.</span><span class="n">reserve</span><span class="p">(</span><span class="k">sizeof</span><span class="p">...(</span><span class="n">Args</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">vec</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Args</span><span class="o">&gt;</span><span class="p">(</span><span class="n">args</span><span class="p">)),</span> <span class="p">...);</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">vec</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>See at <a href="https://godbolt.org/z/jTWxeYWEh">@Compiler Explorer</a></p> <p>When we run the code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;initHelper { }</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">vec</span> <span class="o">=</span> <span class="n">initHelper</span><span class="o">&lt;</span><span class="n">Object</span><span class="o">&gt;</span><span class="p">(</span><span class="s">&#34;John&#34;</span><span class="p">,</span> <span class="s">&#34;Doe&#34;</span><span class="p">,</span> <span class="s">&#34;Jane&#34;</span><span class="p">);</span> </span></span></code></pre></div><p>We&rsquo;ll get the following:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">initHelper { } </span></span><span class="line"><span class="cl">MyType::MyType John </span></span><span class="line"><span class="cl">MyType::MyType Doe </span></span><span class="line"><span class="cl">MyType::MyType Jane </span></span><span class="line"><span class="cl">MyType::~MyType John </span></span><span class="line"><span class="cl">MyType::~MyType Doe </span></span><span class="line"><span class="cl">MyType::~MyType Jane </span></span></code></pre></div><p>What&rsquo;s more, the same function template can be used to initialize from moveable objects:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o">&lt;</span><span class="n">Shape</span><span class="o">&gt;&gt;</span> <span class="n">shapes</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">shapes</span><span class="p">.</span><span class="n">reserve</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">shapes</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="n">Circle</span><span class="o">&gt;</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="n">shapes</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="n">Rectangle</span><span class="o">&gt;</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">shapes2</span> <span class="o">=</span> <span class="n">initHelper</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o">&lt;</span><span class="n">Shape</span><span class="o">&gt;&gt;</span><span class="p">(</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="n">Circle</span><span class="o">&gt;</span><span class="p">(),</span> <span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="n">Rectangle</span><span class="o">&gt;</span><span class="p">());</span> </span></span></code></pre></div><p>Run at <a href="https://godbolt.org/z/GG5f751e4">@Compiler Explorer</a></p> <p>Core features:</p> <ul> <li>Variadic templates allow us to pass any number of arguments into a function and process it with argument pack syntax.</li> <li><code>(vec.emplace_back(std::forward&lt;Args&gt;(args)), ...);</code> is a fold expression over a comma operator that nicely expands the argument pack at compile time. Fold expressions have been available since C++17.</li> </ul> <h2 id="more-proposals"> More proposals <a class="hash-link" href="#more-proposals" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The initializer list is not perfect, and there were several attempts to fix it:</p> <p>From the paper <a href="https://wg21.link/N4166">N4166</a> by David Krauss</p> <blockquote> <p><code>std::initializer_list</code> was designed around 2005 (N1890) to 2007 (N2215), before move semantics matured, around 2009. At the time, it was not anticipated that copy semantics would be insufficient or even suboptimal for common value-like classes. There was a 2008 proposal &ldquo;N2801 Initializer lists and move semantics&rdquo; but C++0x was already felt to be slipping at that time, and by 2011 the case had gone cold.</p> </blockquote> <p>There&rsquo;s also a proposal by Sy Brand: <a href="https://wg21.tartanllama.xyz/initializer_list">WG21 Proposals - init list</a></p> <p>Still, as of 2022, there have yet to be any improvements implemented in the standard. So we have to wait a bit.</p> <p>(<strong>voted into C++26!</strong>): <del>Recently there&rsquo;s also a proposal from Arthur: <a href="https://quuxplusone.github.io/blog/2023/01/13/embed-and-initializer-lists/">P1967 `#embed` and D2752 &ldquo;Static storage for `initializer_list`&rdquo; are now on Compiler Explorer</a>. This is very interesting as it allows us to put that unnamed const array into the static storage rather than on the stack. We&rsquo;ll see how it goes.</del></p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In the article, I showed you three issues with <code>initializer_list</code>: extra copies, lack of support for non-copyable objects, and undefined behavior when returning such lists. The case with non-copyable objects can be solved by using a relatively simple factory function that accepts a variadic pack.</p> <p>What&rsquo;s more, we looked at an improvement from C++26 that allows the compiler to put the backing array for the initializer list in static storage space. This improvement helps with avoiding stack overflows and tricky-to-find bugs.</p> <h3 id="resources"> Resources <a class="hash-link" href="#resources" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <ul> <li><a href="https://learn.microsoft.com/en-us/cpp/standard-library/initializer-list-class?view=msvc-170">initializer_list class</a> - Microsoft Learn</li> <li><a href="https://akrzemi1.wordpress.com/2016/07/07/the-cost-of-stdinitializer_list/">The cost of <code>std::initializer_list</code></a> - Andrzej Krzemieński</li> </ul> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Do you prefer container initialization with <code>initializer_list</code> or regular <code>push_back()</code> or <code>emplace_back()</code>?</li> <li>Do you tend to optimize and reduce temporary copies when possible?</li> </ul> <p>Share your comments below.</p> Boost File Scanning Speed: Query File Attributes on Windows 50x Faster https://www.cppstories.com/2024/cpp-query-file-attribs-faster/ Sun, 11 Aug 2024 00:00:00 +0000 https://www.cppstories.com/2024/cpp-query-file-attribs-faster/ <p>Imagine you&rsquo;re developing a tool that needs to scan for file changes across thousands of project files. Retrieving file attributes efficiently becomes critical for such scenarios. In this article, I&rsquo;ll demonstrate a technique to get file attributes that can achieve a surprising speedup of over 50+ times compared to standard Windows methods.</p> <p>Let&rsquo;s dive in and explore how we can achieve this.</p> <h2 id="inspiration--disclaimer"> Inspiration &amp; Disclaimer <a class="hash-link" href="#inspiration--disclaimer" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>The inspiration for this article came from a recent update for Visual Assist - a tool that heavily improves Visual Studio experience and productivity for C# and C++ developers.</p> <p>In one of their blog post, they shared:</p> <blockquote> <p>The initial parse is 10..15x faster!</p> </blockquote> <p><a href="https://www.wholetomato.com/blog/2024/02/21/whats-new-in-visual-assist-2024-featuring-lightning-fast-parser-performance-webinar/">What’s New in Visual Assist 2024—Featuring lightning fast parser performance [Webinar] - Tomato Soup</a></p> <p>After watching the webinar, I noticed some details about efficiently getting file attributes and I decided to give it a try on my machine. In other words I tried to recreate their results.</p> <p><strong>Disclaimer</strong>: This post was written with the support and sponsorship of Idera, the company behind Visual Assist.</p> <h2 id="understanding-file-attribute-retrieval-methods-on-windows"> Understanding File Attribute Retrieval Methods on Windows <a class="hash-link" href="#understanding-file-attribute-retrieval-methods-on-windows" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>On Windows, there are at least a few options to check for a file change:</p> <ul> <li><code>FindFirstFile[EX]</code></li> <li><code>GetFileAttributesEx</code></li> <li><code>std::filesystem</code></li> </ul> <p>Below, you can see some primary usage of each approach:</p> <h3 id="findfirstfileex"> <code>FindFirstFileEx</code> <a class="hash-link" href="#findfirstfileex" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p><code>FindFirstFileEx</code> is a Windows API function that allows for efficient searching of directories. It retrieves information about files that match a specified file name pattern. The function can be used with different information levels, such as <code>FindExInfoBasic</code> and <code>FindExInfoStandard</code>, to control the amount of file information fetched.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">WIN32_FIND_DATA</span> <span class="n">findFileData</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="n">HANDLE</span> <span class="n">hFind</span> <span class="o">=</span> <span class="n">FindFirstFileEx</span><span class="p">((</span><span class="n">directory</span> <span class="o">+</span> <span class="s">&#34;</span><span class="se">\\</span><span class="s">*&#34;</span><span class="p">).</span><span class="n">c_str</span><span class="p">(),</span> <span class="n">FindExInfoBasic</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">findFileData</span><span class="p">,</span> <span class="n">FindExSearchNameMatch</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">hFind</span> <span class="o">!=</span> <span class="n">INVALID_HANDLE_VALUE</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">do</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Process file information </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">FindNextFile</span><span class="p">(</span><span class="n">hFind</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">findFileData</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">FindClose</span><span class="p">(</span><span class="n">hFind</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><h3 id="getfileattributesex"> <code>GetFileAttributesEx</code> <a class="hash-link" href="#getfileattributesex" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p><code>GetFileAttributesEx</code> is another Windows API function that retrieves file attributes for a specified file or directory. Unlike <code>FindFirstFileEx</code>, which is used for searching and listing files, <code>GetFileAttributesEx</code> is typically used for retrieving attributes of a single file or directory.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">WIN32_FILE_ATTRIBUTE_DATA</span> <span class="n">fileAttributeData</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">GetFileAttributesEx</span><span class="p">((</span><span class="n">directory</span> <span class="o">+</span> <span class="s">&#34;</span><span class="se">\\</span><span class="s">&#34;</span> <span class="o">+</span> <span class="n">fileName</span><span class="p">).</span><span class="n">c_str</span><span class="p">(),</span> <span class="n">GetFileExInfoStandard</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">fileAttributeData</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Process file attributes </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span></code></pre></div><h4 id="stdfilesystem"> <code>std::filesystem</code> </h4> <p>Introduced in C++17, the <code>std::filesystem</code> library provides a modern and portable way to interact with the file system. It includes functions for file attribute retrieval, directory iteration, and other common file system operations.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">fs</span><span class="o">::</span><span class="n">directory_iterator</span><span class="p">(</span><span class="n">directory</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">is_regular_file</span><span class="p">())</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Process file attributes </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">auto</span> <span class="n">ftime</span> <span class="o">=</span> <span class="nl">fs</span><span class="p">:</span><span class="n">last_write_time</span><span class="p">(</span><span class="n">entry</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">...</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><h2 id="the-benchmark"> The Benchmark <a class="hash-link" href="#the-benchmark" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>To evaluate the performance of different file attribute retrieval methods, I developed a small benchmark. This application measures the time taken by each method to retrieve file attributes for N number of files in a specified directory.</p> <p>Here&rsquo;s a rough overview of the code:</p> <p>The <code>FileInfo</code> struct stores the file name and last write time.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">FileInfo</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">fileName</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">FILETIME</span> <span class="n">lastWriteTime</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span></code></pre></div><p>Each retrieval technique will have to go over a directory and build a vector of <code>FileInfo</code> objects.</p> <h4 id="benchmarkfindfirstfileex"> <code>BenchmarkFindFirstFileEx</code> </h4> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">BenchmarkFindFirstFileEx</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">directory</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">FileInfo</span><span class="o">&gt;&amp;</span> <span class="n">files</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">FINDEX_INFO_LEVELS</span> <span class="n">infoLevel</span><span class="p">)</span> </span></span><span class="line"><span class="cl"><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">WIN32_FIND_DATA</span> <span class="n">findFileData</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">HANDLE</span> <span class="n">hFind</span> <span class="o">=</span> <span class="n">FindFirstFileEx</span><span class="p">((</span><span class="n">directory</span> <span class="o">+</span> <span class="s">&#34;</span><span class="se">\\</span><span class="s">*&#34;</span><span class="p">).</span><span class="n">c_str</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="n">infoLevel</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="o">&amp;</span><span class="n">findFileData</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">FindExSearchNameMatch</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">hFind</span> <span class="o">==</span> <span class="n">INVALID_HANDLE_VALUE</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;FindFirstFileEx failed (&#34;</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="n">GetLastError</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">do</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">findFileData</span><span class="p">.</span><span class="n">dwFileAttributes</span> <span class="o">&amp;</span> <span class="n">FILE_ATTRIBUTE_DIRECTORY</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">FileInfo</span> <span class="n">fileInfo</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">fileInfo</span><span class="p">.</span><span class="n">fileName</span> <span class="o">=</span> <span class="n">findFileData</span><span class="p">.</span><span class="n">cFileName</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">fileInfo</span><span class="p">.</span><span class="n">lastWriteTime</span> <span class="o">=</span> <span class="n">findFileData</span><span class="p">.</span><span class="n">ftLastWriteTime</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">files</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">fileInfo</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">FindNextFile</span><span class="p">(</span><span class="n">hFind</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">findFileData</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">FindClose</span><span class="p">(</span><span class="n">hFind</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><h4 id="benchmarkgetfileattributesex"> <code>BenchmarkGetFileAttributesEx</code> </h4> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">BenchmarkGetFileAttributesEx</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">directory</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">FileInfo</span><span class="o">&gt;&amp;</span> <span class="n">files</span><span class="p">)</span> </span></span><span class="line"><span class="cl"><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">WIN32_FIND_DATA</span> <span class="n">findFileData</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">HANDLE</span> <span class="n">hFind</span> <span class="o">=</span> <span class="n">FindFirstFile</span><span class="p">((</span><span class="n">directory</span> <span class="o">+</span> <span class="s">&#34;</span><span class="se">\\</span><span class="s">*&#34;</span><span class="p">).</span><span class="n">c_str</span><span class="p">(),</span> </span></span><span class="line"><span class="cl"> <span class="o">&amp;</span><span class="n">findFileData</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">hFind</span> <span class="o">==</span> <span class="n">INVALID_HANDLE_VALUE</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;FindFirstFile failed (&#34;</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="n">GetLastError</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">do</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">findFileData</span><span class="p">.</span><span class="n">dwFileAttributes</span> <span class="o">&amp;</span> <span class="n">FILE_ATTRIBUTE_DIRECTORY</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">WIN32_FILE_ATTRIBUTE_DATA</span> <span class="n">fileAttributeData</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">GetFileAttributesEx</span><span class="p">((</span><span class="n">directory</span> <span class="o">+</span> <span class="s">&#34;</span><span class="se">\\</span><span class="s">&#34;</span> <span class="o">+</span> <span class="n">findFileData</span><span class="p">.</span><span class="n">cFileName</span><span class="p">).</span><span class="n">c_str</span><span class="p">(),</span> <span class="n">GetFileExInfoStandard</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">fileAttributeData</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">FileInfo</span> <span class="n">fileInfo</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">fileInfo</span><span class="p">.</span><span class="n">fileName</span> <span class="o">=</span> <span class="n">findFileData</span><span class="p">.</span><span class="n">cFileName</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">fileInfo</span><span class="p">.</span><span class="n">lastWriteTime</span> <span class="o">=</span> <span class="n">fileAttributeData</span><span class="p">.</span><span class="n">ftLastWriteTime</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">files</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">fileInfo</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">FindNextFile</span><span class="p">(</span><span class="n">hFind</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">findFileData</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">FindClose</span><span class="p">(</span><span class="n">hFind</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><h4 id="benchmarkstdfilesystem"> <code>BenchmarkStdFilesystem</code> </h4> <p>And the last one, the most portable technique:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">BenchmarkStdFilesystem</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">directory</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">FileInfo</span><span class="o">&gt;&amp;</span> <span class="n">files</span><span class="p">)</span> </span></span><span class="line"><span class="cl"><span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">directory_iterator</span><span class="p">(</span><span class="n">directory</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">is_regular_file</span><span class="p">())</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">FileInfo</span> <span class="n">fileInfo</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">fileInfo</span><span class="p">.</span><span class="n">fileName</span> <span class="o">=</span> <span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">().</span><span class="n">filename</span><span class="p">().</span><span class="n">string</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">ftime</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">last_write_time</span><span class="p">(</span><span class="n">entry</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">memcpy</span><span class="p">(</span><span class="o">&amp;</span><span class="n">fileInfo</span><span class="p">.</span><span class="n">lastWriteTime</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ftime</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">FILETIME</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="n">files</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">fileInfo</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>In the code, we use the assumption that file_time_type values maps to <code>FILETIME</code> on Windows. Read more in this explanation <a href="https://developercommunity.visualstudio.com/t/stdfilesystemfile-time-type-does-not-allow-easy-co/251213">std::filesystem::file_time_type does not allow easy conversion to time_t - Developer Community</a></p> <h4 id="the-main-function"> The Main Function </h4> <p>The <code>main</code> function sets up the benchmarking environment, runs the benchmarks, and prints the results.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Benchmark FindFirstFileEx (Basic) </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">start</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">high_resolution_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="n">BenchmarkFindFirstFileEx</span><span class="p">(</span><span class="n">directory</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">filesFindFirstFileExBasic</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">FindExInfoBasic</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">end</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">high_resolution_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">duration</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span> <span class="n">elapsedFindFirstFileExBasic</span> <span class="o">=</span> <span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// Benchmark FindFirstFileEx (Standard) </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">start</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">high_resolution_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="n">BenchmarkFindFirstFileEx</span><span class="p">(</span><span class="n">directory</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">filesFindFirstFileExStandard</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">FindExInfoStandard</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="n">end</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">high_resolution_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">duration</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span> <span class="n">elapsedFindFirstFileExStandard</span> <span class="o">=</span> <span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// ... </span></span></span></code></pre></div><p>This benchmark code measures the performance of <code>FindFirstFileEx</code> with both <code>FindExInfoBasic</code> and <code>FindExInfoStandard</code>, <code>GetFileAttributesEx</code>, and <code>std::filesystem</code>. The results are then formatted and displayed in a table.</p> <h2 id="performance-results"> Performance Results <a class="hash-link" href="#performance-results" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>To measure the performance of each file attribute retrieval method, I executed benchmarks on a directory containing 1000, 2000 or 5000 random text files. The tests were performed on a laptop equipped with an Intel i7 4720HQ CPU and an SSD. I measured the time taken by each method and compared the results to determine the fastest approach.</p> <p>Each test run consisted of two executions: the first with uncached file attributes and the second likely benefiting from system-level caching.</p> <p>The speedup factor is the factor of the current result compared to the slowest technique in a given run.</p> <p>1000 files:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Method Time (seconds) Speedup Factor </span></span><span class="line"><span class="cl">FindFirstFileEx (Basic) 0.0131572000 17.876 </span></span><span class="line"><span class="cl">FindFirstFileEx (Standard) 0.0018139000 129.665 </span></span><span class="line"><span class="cl">GetFileAttributesEx 0.2351992000 1.000 </span></span><span class="line"><span class="cl">std::filesystem 0.0607928000 3.869 </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">Method Time (seconds) Speedup Factor </span></span><span class="line"><span class="cl">FindFirstFileEx (Basic) 0.0009740000 61.956 </span></span><span class="line"><span class="cl">FindFirstFileEx (Standard) 0.0009998000 60.358 </span></span><span class="line"><span class="cl">GetFileAttributesEx 0.0602633000 1.001 </span></span><span class="line"><span class="cl">std::filesystem 0.0603455000 1.000 </span></span></code></pre></div><p>Directory with 2000 files:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Method Time (seconds) Speedup Factor </span></span><span class="line"><span class="cl">FindFirstFileEx (Basic) 0.0023182000 54.402 </span></span><span class="line"><span class="cl">FindFirstFileEx (Standard) 0.0044334000 28.446 </span></span><span class="line"><span class="cl">GetFileAttributesEx 0.1261137000 1.000 </span></span><span class="line"><span class="cl">std::filesystem 0.1259038000 1.002 </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">Method Time (seconds) Speedup Factor </span></span><span class="line"><span class="cl">FindFirstFileEx (Basic) 0.0022301000 55.417 </span></span><span class="line"><span class="cl">FindFirstFileEx (Standard) 0.0040665000 30.391 </span></span><span class="line"><span class="cl">GetFileAttributesEx 0.1235858000 1.000 </span></span><span class="line"><span class="cl">std::filesystem 0.1220140000 1.013 </span></span></code></pre></div><p>Directory with 5000 random, small text files:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Method Time (seconds) Speedup Factor </span></span><span class="line"><span class="cl">FindFirstFileEx (Basic) 0.0059723000 113.144 </span></span><span class="line"><span class="cl">FindFirstFileEx (Standard) 0.0125500000 53.843 </span></span><span class="line"><span class="cl">GetFileAttributesEx 0.6757297000 1.000 </span></span><span class="line"><span class="cl">std::filesystem 0.3098593000 2.181 </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">Method Time (seconds) Speedup Factor </span></span><span class="line"><span class="cl">FindFirstFileEx (Basic) 0.0060349000 52.300 </span></span><span class="line"><span class="cl">FindFirstFileEx (Standard) 0.0136566000 23.112 </span></span><span class="line"><span class="cl">GetFileAttributesEx 0.3156277000 1.000 </span></span><span class="line"><span class="cl">std::filesystem 0.3075732000 1.026 </span></span></code></pre></div><p>The results consistently showed that <code>FindFirstFileEx</code> with the <code>Standard</code> flag was the fastest method in uncached scenarios, offering speedups up to 129x compared to <code>GetFileAttributesEx</code>. However, in cached scenarios, <code>FindFirstFileEx</code> (Basic and Standard) achieved over 50x speedup improvements.</p> <p>For the directory with 2000 files, <code>FindFirstFileEx</code> (Basic) demonstrated a speedup factor of over 54x in the first run and maintained similar performance in the second run. In the directory with 5000 files, the <code>Basic</code> version achieved an impressive 113x speedup initially and 52x in the subsequent run, reflecting the impact of caching. Notably, <code>std::filesystem</code> performed on par with <code>GetFileAttributesEx</code>.</p> <h2 id="further-techniques"> Further Techniques <a class="hash-link" href="#further-techniques" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Getting file attributes is only part of the story, and while important, they may contribute to only a small portion of the overall performance for the whole project. The Visual Assist team, who contributed to this article, improved their initial parse time performance by avoiding <code>GetFileAttributes[Ex]</code> using the same techniques as this article. But Visual Assist also improved performance through further techniques. My simple benchmark showed 50x speedups, but we cannot directly compare it with the final Visual Assist, as the tool does many more things with files.</p> <p>The main item being optimised was the initial parse, where VA builds a symbol database when a project is opened for the first time. This involves parsing all code and all headers. They decided that it&rsquo;s a reasonable assumption that headers won&rsquo;t change while a project is being loaded, and so the file access is cached during the initial parse, avoiding the filesystem entirely. (Changes after a project has been parsed the first time are, of course, still caught.) The combination of switching to a much faster method for checking filetimes and then avoiding file IO completely contributed to the up-to-15-times-faster performance improvement they saw in version 2024.1 at the beginning of this year.</p> <p>Read further details on their blog <a href="https://www.wholetomato.com/blog/2024/01/31/visual-assist-2024-1-release-post/">Visual Assist 2024.1 release post - January 2024</a> and <a href="https://www.wholetomato.com/blog/2024/07/21/catching-up-with-va-our-most-recent-performance-updates/">Catching up with VA: Our most recent performance updates - Tomato Soup</a>.</p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In the text, we went through a benchmark that compares several techniques for fetching file attributes. In short, it&rsquo;s best to gather attributes at the same time as you iterate through the directory - using <code>FindFirstFileEx</code>. So if you want to do this operation hundreds of times, it&rsquo;s best to measure time and choose the best technique.</p> <p>The benchmark also showed one feature: while C++17 and its <code>filesystem</code> library offer a robust and standardized way to work with files and directories, it can be limited in terms of performance. In many cases, if you need super optimal performance, you need to open the hood and work with the specific operating system API.</p> <p>The code can be found in my Github Respository: <a href="https://github.com/fenbf/articles/blob/master/file_attribs_test/FileAttribsTest.cpp">FileAttribsTest.cpp</a></p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Do you use std::filesystem for tasks involving hundreds of files?</li> <li>Do you know other techniques that offer greater performance when working with files?</li> </ul> <p>Share your comments below.</p> Enum Class Improvements for C++17, C++20 and C++23 https://www.cppstories.com/2024/enum-improvements/ Sun, 04 Aug 2024 00:00:00 +0000 https://www.cppstories.com/2024/enum-improvements/ <p>The evolution of the C++ language continues to bring powerful features that enhance code safety, readability, and maintainability. Among these improvements, we got changes and additions to <code>enum class</code> functionalities across C++17, C++20, and C++23. In this blog post, we&rsquo;ll explore these advancements, focusing on initialization improvements in C++17, the introduction of the <code>using enum</code> keyword in C++20, and the <code>std::to_underlying</code> utility in C++23.</p> <p>Let&rsquo;s go.</p> <h2 id="enum-class-recap"> Enum Class Recap <a class="hash-link" href="#enum-class-recap" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Before diving into the enhancements, let&rsquo;s briefly recap what <code>enum class</code> is. An <code>enum class</code> (scoped enumeration) provides a type-safe way of defining a set of named constants. Unlike traditional (unscoped) enums, <code>enum class</code> does not implicitly convert to integers or other types, preventing accidental misuse. Here&rsquo;s a basic example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="k">class</span> <span class="nc">Color</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Red</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">Green</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">Blue</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Color</span> <span class="n">color</span> <span class="o">=</span> <span class="n">Color</span><span class="o">::</span><span class="n">Red</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">color</span> <span class="o">==</span> <span class="n">Color</span><span class="o">::</span><span class="n">Red</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;The color is red.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">color</span> <span class="o">=</span> <span class="n">Color</span><span class="o">::</span><span class="n">Blue</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">color</span> <span class="o">==</span> <span class="n">Color</span><span class="o">::</span><span class="n">Blue</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;The color is blue.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// std::cout &lt;&lt; color; // error, no matching &lt;&lt; operator </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="c1">// int i = color; // error: cannot convert </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/c4P6n8z9Y">@Compiler Explorer</a></p> <p>Notice the two lines near the end of the <code>main</code> function. You&rsquo;ll get compiler errors as there&rsquo;s no implicit conversion to integer types.</p> <p>As a comparison here&rsquo;s a similar example, but with unscoped enums:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="nc">Color</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Red</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">Green</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">Blue</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Color</span> <span class="n">color</span> <span class="o">=</span> <span class="n">Red</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">color</span> <span class="o">==</span> <span class="n">Red</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;The color is red.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">color</span> <span class="o">=</span> <span class="n">Blue</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">color</span> <span class="o">==</span> <span class="n">Blue</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;The color is blue.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">color</span><span class="p">;</span> <span class="c1">// fine, prints integer value! </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">color</span><span class="p">;</span> <span class="c1">// fine, can convert... </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/xaorMje9W">@Compiler Explorer</a></p> <p>In short, while <code>enum classes</code> give us a separate scope for all of the enum values, they also enforce better type safety. There are no implicit conversions to integral values, and thus, you have better control over your design.</p> <p>While the basics are simple, let&rsquo;s now go to several improvements that are handy in the latest C++ revisions.</p> <h2 id="c17-initialization-with-brace-initialization-from-underlying-type"> C++17: Initialization with Brace Initialization from Underlying Type <a class="hash-link" href="#c17-initialization-with-brace-initialization-from-underlying-type" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>Enum class might sometimes feel too restrictive, and having some conversions might be handy:</p> <p>In <a href="https://wg21.link/P0138R2">P0138</a> accepted for C++17 we have the following example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">enum</span> <span class="k">class</span> <span class="nc">Handle</span> <span class="o">:</span> <span class="kt">uint32_t</span> <span class="p">{</span> <span class="n">Invalid</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="n">Handle</span> <span class="n">h</span> <span class="p">{</span> <span class="mi">42</span> <span class="p">};</span> <span class="c1">// OK </span></span></span></code></pre></div><p>In short, when you use <code>enum class</code> to define strong types, it&rsquo;s helpful to allow initializing from the underlying type without any errors. This wasn&rsquo;t possible before C++17.</p> <p>However, the change was cautious so that enums are still safe - they can be used only for uniform/brace initialization. Have a look at this code:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="k">class</span> <span class="nc">Handle</span> <span class="o">:</span> <span class="kt">uint32_t</span> <span class="p">{</span> <span class="n">Invalid</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">process</span><span class="p">(</span><span class="n">Handle</span> <span class="n">h</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Handle</span> <span class="n">h</span> <span class="p">{</span> <span class="mi">42</span> <span class="p">};</span> <span class="c1">// OK </span></span></span><span class="line"><span class="cl"><span class="c1"></span> </span></span><span class="line"><span class="cl"> <span class="c1">// process({10}); // error </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">process</span><span class="p">(</span><span class="n">Handle</span><span class="p">{</span><span class="mi">10</span><span class="p">});</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>You cannot just pass <code>{10}</code> as the parameter for the <code>process</code> function. You still have to be explicit about the type.</p> <p>In C++14, you could use <code>process(static_cast&lt;Handle&gt;(10));</code> so, as you can see, the C++17 version is much better.</p> <h2 id="c20-using-enum"> C++20: Using Enum <a class="hash-link" href="#c20-using-enum" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>C++20 introduced the <code>using enum</code> syntax. This feature allows you to bring all the enumerators of an enum into the current scope without losing the benefits of scoped enums.</p> <p>Consider the following example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">enum</span> <span class="k">class</span> <span class="nc">ComputeStatus</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Ok</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">Error</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">FileError</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">NotEnoughMemory</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">TimeExceeded</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">Unknown</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span></code></pre></div><p>In previous C++ versions, using these enumerators required qualifying them with the enum class name:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ComputeStatus</span> <span class="n">s</span> <span class="o">=</span> <span class="n">ComputeStatus</span><span class="o">::</span><span class="n">NotEnoughMemory</span><span class="p">;</span> </span></span></code></pre></div><p>C++20 simplifies this with the <code>using enum</code> declaration:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">enum</span> <span class="nc">ComputeStatus</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">ComputeStatus</span> <span class="n">s</span> <span class="o">=</span> <span class="n">NotEnoughMemory</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>It&rsquo;s probably no sense in this silly code above, but how about the following case:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">ComputeStatus</span> <span class="n">s</span> <span class="o">=</span> <span class="n">ComputeStatus</span><span class="o">::</span><span class="n">Ok</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">switch</span> <span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="n">ComputeStatus</span><span class="o">::</span><span class="nl">Ok</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;ok&#34;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="n">ComputeStatus</span><span class="o">::</span><span class="nl">Error</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Error&#34;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="n">ComputeStatus</span><span class="o">::</span><span class="nl">FileError</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;FileError&#34;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="n">ComputeStatus</span><span class="o">::</span><span class="nl">NotEnoughMemory</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;NotEnoughMemory&#34;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="n">ComputeStatus</span><span class="o">::</span><span class="nl">TimeExceeded</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Time...&#34;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">default</span><span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;unknown...&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>We can convert it into:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">ComputeStatus</span> <span class="n">s</span> <span class="o">=</span> <span class="n">ComputeStatus</span><span class="o">::</span><span class="n">Ok</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">switch</span> <span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">enum</span> <span class="nc">ComputeStatus</span><span class="p">;</span> <span class="c1">// &lt;&lt; &lt;&lt; </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">case</span> <span class="nl">Ok</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;ok&#34;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="nl">Error</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Error&#34;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="nl">FileError</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;FileError&#34;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="nl">NotEnoughMemory</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;NotEnoughMemory&#34;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="nl">TimeExceeded</span><span class="p">:</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Time...&#34;</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">default</span><span class="o">:</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;unknown...&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/fdjEThd8Y">@Compiler Explorer</a></p> <p>Or have a look at the following example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">ComputeEngine</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">enum</span> <span class="k">class</span> <span class="nc">ComputeStatus</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Ok</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">Error</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">FileError</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">NotEnoughMemory</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">TimeExceeded</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">Unknown</span> </span></span><span class="line"><span class="cl"> <span class="p">};</span> </span></span><span class="line"><span class="cl"> <span class="k">using</span> <span class="k">enum</span> <span class="nc">ComputeStatus</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">ComputeEngine</span><span class="o">::</span><span class="n">ComputeStatus</span> <span class="n">s</span> <span class="o">=</span> <span class="n">ComputeEngine</span><span class="o">::</span><span class="n">Ok</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>You can bring all enumerations into the scope of <code>ComputeEngine</code> and still benefit from <code>enum class</code> features.</p> <p>This C++20 improvement makes the code cleaner and reduces verbosity, especially in cases where multiple enumerators are frequently used within a scope. It allows for a more streamlined and readable approach without sacrificing the type safety provided by scoped enums.</p> <h2 id="c23-stdto_underlying"> C++23: <code>std::to_underlying</code> <a class="hash-link" href="#c23-stdto_underlying" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>C++23 further enhances enum class usability with the introduction of <code>std::to_underlying</code>, a utility function that converts an enum value to its underlying integral type. This feature addresses the common need to convert enum values to integers for storage, comparison, or interoperability with APIs that expect integral types.</p> <p>The idea for this appeared in a wonderful book by Scott Meyers - <a href="https://amzn.to/3t5tmS4">Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14</a>. Finally in C++23 we can enjoy this feature being standardized.</p> <p>Before C++23, converting an enum to its underlying type required explicit casting:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">enum</span> <span class="k">class</span> <span class="nc">Permissions</span> <span class="o">:</span> <span class="kt">uint8_t</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Execute</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">Write</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">Read</span> <span class="o">=</span> <span class="mi">4</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">uint8_t</span> <span class="n">value</span> <span class="o">=</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="kt">uint8_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">Permissions</span><span class="o">::</span><span class="n">Read</span><span class="p">);</span> </span></span></code></pre></div><p>With <code>std::to_underlying</code>, this conversion becomes more straightforward and expressive:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;type_traits&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">Permissions</span> <span class="n">p</span> <span class="o">=</span> <span class="n">Permissions</span><span class="o">::</span><span class="n">Read</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">value</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">to_underlying</span><span class="p">(</span><span class="n">p</span><span class="p">);</span> <span class="c1">// C++23 </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> </span></span></code></pre></div><p>The <code>std::to_underlying</code> function improves code readability and reduces the boilerplate associated with type casting. It also clarifies the intent, making it evident that the purpose is to obtain the underlying value of the <code>enum</code>.</p> <p>Read more in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1682r0.html">P1682R0: std::to_underlying for enumerations</a></p> <p>If you want to read more about bitmasks, have a look at this cool article by Andreas Fertig: <a href="https://andreasfertig.blog/2024/01/cpp20-concepts-applied/">C++20 Concepts applied - Safe bitmasks using scoped enums - Andreas Fertig&rsquo;s Blog</a>.</p> <h2 id="future-improvements"> Future improvements <a class="hash-link" href="#future-improvements" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>One important update that we may receive soon is support for C++26 reflections - check out <a href="https://wg21.link/P2996">P2996</a> (the proposal has not been accepted yet, but is expected to be approved soon&hellip;). Reflection opens up numerous exciting possibilities, such as the ability to convert enums into strings.</p> <p>See this example from the proposal:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">E</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"> <span class="k">requires</span> <span class="n">std</span><span class="o">::</span><span class="n">is_enum_v</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> </span></span><span class="line"><span class="cl"><span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">enum_to_string</span><span class="p">(</span><span class="n">E</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">template</span> <span class="nf">for</span> <span class="p">(</span><span class="k">constexpr</span> <span class="k">auto</span> <span class="nl">e</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">meta</span><span class="o">::</span><span class="n">enumerators_of</span><span class="p">(</span><span class="o">^</span><span class="n">E</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">value</span> <span class="o">==</span> <span class="p">[</span><span class="o">:</span><span class="nl">e</span><span class="p">:])</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">meta</span><span class="o">::</span><span class="n">name_of</span><span class="p">(</span><span class="n">e</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s">&#34;&lt;unnamed&gt;&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="nc">Color</span> <span class="p">{</span> <span class="n">red</span><span class="p">,</span> <span class="n">green</span><span class="p">,</span> <span class="n">blue</span> <span class="p">};</span> </span></span><span class="line"><span class="cl"><span class="k">static_assert</span><span class="p">(</span><span class="n">enum_to_string</span><span class="p">(</span><span class="n">Color</span><span class="o">::</span><span class="n">red</span><span class="p">)</span> <span class="o">==</span> <span class="s">&#34;red&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="k">static_assert</span><span class="p">(</span><span class="n">enum_to_string</span><span class="p">(</span><span class="n">Color</span><span class="p">(</span><span class="mi">42</span><span class="p">))</span> <span class="o">==</span> <span class="s">&#34;&lt;unnamed&gt;&#34;</span><span class="p">);</span> </span></span></code></pre></div><p>See at <a href="https://godbolt.org/z/Y5va8MqzG">EDG experimental implementation</a> @CompilerExplorer</p> <p>Of course, you don&rsquo;t have to wait till C++26 and you can rely on third-party libraries like <a href="https://github.com/Neargye/magic_enum"><code>Neargye/magic_enum</code> @Github</a>. (Thanks to mentioning that in the comment, <a href="https://github.com/maxpagani">maxpagani</a>).</p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In this article, we covered some of the new features introduced in C++17, C++20, and C++23 for enum classes. Enum classes provide type safety, but there are situations where we may need to relax some restrictions and write more concise code. We also explored the potential use case for C++26 reflection.</p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Have you tried the latest improvements for <code>enum class</code>?</li> <li>Do you use <code>enum class</code> for strong types or some other techniques?</li> </ul> <p>Share your feedback below in the comments.</p> 22 Common Filesystem Tasks in C++20 https://www.cppstories.com/2024/common-filesystem-cpp20/ Sun, 14 Jul 2024 00:00:00 +0000 https://www.cppstories.com/2024/common-filesystem-cpp20/ <p>Working with the filesystem can be a daunting task, but it doesn&rsquo;t have to be. In this post, I&rsquo;ll walk you through some of the most common filesystem operations using the powerful features introduced in C++17, as well as some new enhancements in C++20/23. Whether you&rsquo;re creating directories, copying files, or managing permissions, these examples will help you understand and efficiently utilize the <code>std::filesystem</code> library.</p> <p>Let&rsquo;s start.</p> <h2 id="directory-operations"> Directory Operations <a class="hash-link" href="#directory-operations" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <h3 id="1-creating-directories"> 1. Creating Directories <a class="hash-link" href="#1-creating-directories" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Creating directories is a basic yet essential operation. The <code>std::filesystem</code> library makes this straightforward with the <code>create_directory</code> function.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">dir</span> <span class="o">=</span> <span class="s">&#34;example_directory&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directory</span><span class="p">(</span><span class="n">dir</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Directory created successfully</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Failed to create directory</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Ron <a href="https://godbolt.org/z/z4YYnPTb5">@Compiler Explorer</a></p> <p>The function returns <code>true</code> when the directory was newly created. But it can also throw an exception in case of an error. You can use <code>noexcept</code> version of this function:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">create_directory</span><span class="p">(</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">error_code</span><span class="o">&amp;</span> <span class="n">ec</span> <span class="p">)</span> <span class="k">noexcept</span><span class="p">;</span> </span></span></code></pre></div><p>For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">dir</span> <span class="o">=</span> <span class="s">&#34;/abc/cde&#34;</span><span class="p">;</span> <span class="c1">// recursive? </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">error_code</span> <span class="n">ec</span><span class="p">{};</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directory</span><span class="p">(</span><span class="n">dir</span><span class="p">,</span> <span class="n">ec</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Directory created successfully</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Failed to create directory</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">ec</span><span class="p">.</span><span class="n">message</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/e7q9aWq5x">@Compiler Explorer</a></p> <p>Possible output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Failed to create directory: No such file or directory </span></span><span class="line"><span class="cl">... </span></span></code></pre></div><p>See more <a href="https://en.cppreference.com/w/cpp/filesystem/create_directory">@Cppreference</a></p> <h3 id="2-creating-nested-directories"> 2. Creating Nested Directories <a class="hash-link" href="#2-creating-nested-directories" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>When you need to create multiple nested directories, use the <code>create_directories</code> function.</p> <p>This function creates directories recursively.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;exception&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">nested</span> <span class="o">=</span> <span class="s">&#34;a/b/c&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directories</span><span class="p">(</span><span class="n">nested</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Nested directories created successfully</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Failed to create nested directories</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">ex</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/dqnx43WYa">@Compiler Explorer</a>.</p> <h3 id="3-removing-a-directory"> 3. Removing a Directory <a class="hash-link" href="#3-removing-a-directory" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>So far, our example directories were left in a vacuum (and I hope Compiler Explorer can safely remove them :), but we can also do it manually from code: We just need the <code>remove</code> function for this task.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;exception&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">ls</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="p">...</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">dir</span> <span class="o">=</span> <span class="s">&#34;test&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directory</span><span class="p">(</span><span class="n">dir</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Directory created successfully</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Failed to create directory</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">ls</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">remove</span><span class="p">(</span><span class="n">dir</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Directory removed</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Failed to remove the directory...</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">ls</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">ex</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Possible output <a href="https://godbolt.org/z/6faMrPPTv">@Compiler Explorer</a>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Directory created successfully </span></span><span class="line"><span class="cl">&#34;./compilation-result.json&#34; </span></span><span class="line"><span class="cl">&#34;./output.s&#34; </span></span><span class="line"><span class="cl">&#34;./example.cpp&#34; </span></span><span class="line"><span class="cl">&#34;./test&#34; </span></span><span class="line"><span class="cl">Directory removed </span></span><span class="line"><span class="cl">&#34;./compilation-result.json&#34; </span></span><span class="line"><span class="cl">&#34;./output.s&#34; </span></span><span class="line"><span class="cl">&#34;./example.cpp&#34; </span></span></code></pre></div><h3 id="4-removing-all-contents-of-a-directory"> 4. Removing All Contents of a Directory <a class="hash-link" href="#4-removing-all-contents-of-a-directory" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>To remove a directory along with all its contents, use the <code>remove_all</code> function.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;exception&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;format&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">ls</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">recursive_directory_iterator</span><span class="p">(</span><span class="s">&#34;.&#34;</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">dir</span> <span class="o">=</span> <span class="s">&#34;test&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">nested</span> <span class="o">=</span> <span class="n">dir</span> <span class="o">/</span> <span class="s">&#34;a/b&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">more</span> <span class="o">=</span> <span class="n">dir</span> <span class="o">/</span> <span class="s">&#34;x/y&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directories</span><span class="p">(</span><span class="n">nested</span><span class="p">)</span> <span class="o">&amp;&amp;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directories</span><span class="p">(</span><span class="n">more</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Directories created successfully</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Failed to create directories...</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">ls</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="k">auto</span> <span class="n">cnt</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">remove_all</span><span class="p">(</span><span class="n">dir</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&#34;removed {} items</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">cnt</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">ls</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">ex</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Possible output <a href="https://godbolt.org/z/r3KWvj5qa">@Compiler Explorer</a>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Directories created successfully </span></span><span class="line"><span class="cl">&#34;./compilation-result.json&#34; </span></span><span class="line"><span class="cl">&#34;./output.s&#34; </span></span><span class="line"><span class="cl">&#34;./example.cpp&#34; </span></span><span class="line"><span class="cl">&#34;./test&#34; </span></span><span class="line"><span class="cl">&#34;./test/x&#34; </span></span><span class="line"><span class="cl">&#34;./test/x/y&#34; </span></span><span class="line"><span class="cl">&#34;./test/a&#34; </span></span><span class="line"><span class="cl">&#34;./test/a/b&#34; </span></span><span class="line"><span class="cl">removed 5 items </span></span><span class="line"><span class="cl">&#34;./compilation-result.json&#34; </span></span><span class="line"><span class="cl">&#34;./output.s&#34; </span></span><span class="line"><span class="cl">&#34;./example.cpp&#34; </span></span></code></pre></div><p>Notice that we had <code>test/x/y</code>, <code>test/x</code>, <code>test/a/b</code>, <code>test/a</code> and <code>test</code> directories to remove in this case.</p> <h3 id="5-listing-directory-contents"> 5. Listing Directory Contents <a class="hash-link" href="#5-listing-directory-contents" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>In my previous examples, I&rsquo;ve used the magical <code>ls()</code> function, but the implementation is quite simple. It uses <code>directory_iterator</code> to iterate through the directory:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;exception&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;format&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">ls</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">directory_iterator</span><span class="p">(</span><span class="s">&#34;.&#34;</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">ls</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>The iterator takes the <code>path</code> object and iterates through files in unspecified order (system dependent).</p> <p>Here&rsquo;s a possible output <a href="https://godbolt.org/z/38Pcf1rTv">@Compiler Explorer</a>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&#34;./compilation-result.json&#34; </span></span><span class="line"><span class="cl">&#34;./output.s&#34; </span></span><span class="line"><span class="cl">&#34;./example.cpp&#34; </span></span></code></pre></div><h3 id="6-listing-directory-contents-recursively"> 6. Listing Directory Contents Recursively <a class="hash-link" href="#6-listing-directory-contents-recursively" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>We can use a recursive version of the <code>directory_iterator</code> to iterate through a whole subtree:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">ls</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">recursive_directory_iterator</span><span class="p">(</span><span class="s">&#34;.&#34;</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directories</span><span class="p">(</span><span class="s">&#34;a/b/c&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directories</span><span class="p">(</span><span class="s">&#34;x/y/z&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">ls</span><span class="p">();</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/cx1joM5fd">@Compiler Explorer</a>. Here&rsquo;s a possible output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&#34;./compilation-result.json&#34; </span></span><span class="line"><span class="cl">&#34;./output.s&#34; </span></span><span class="line"><span class="cl">&#34;./x&#34; </span></span><span class="line"><span class="cl">&#34;./x/y&#34; </span></span><span class="line"><span class="cl">&#34;./x/y/z&#34; </span></span><span class="line"><span class="cl">&#34;./example.cpp&#34; </span></span><span class="line"><span class="cl">&#34;./a&#34; </span></span><span class="line"><span class="cl">&#34;./a/b&#34; </span></span><span class="line"><span class="cl">&#34;./a/b/c&#34; </span></span></code></pre></div><p>If we need a nicer output, we can try implementing our own recursive version:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">ls</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">tabs</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">directory_iterator</span><span class="p">(</span><span class="n">p</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">tabs</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">(</span><span class="n">tabs</span><span class="p">,</span> <span class="sc">&#39;-&#39;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">().</span><span class="n">stem</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">is_directory</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="n">ls</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">(),</span> <span class="n">tabs</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directories</span><span class="p">(</span><span class="s">&#34;a/b/c&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directories</span><span class="p">(</span><span class="s">&#34;x/y/z&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">ls</span><span class="p">(</span><span class="s">&#34;.&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/oz1nGGWsr">@Compiler Explorer</a></p> <p>In this version, I used the <code>is_directory()</code> member function of the <code>directory_entry</code> to check if the item is another directory.</p> <p>The output looks a bit better:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&#34;compilation-result&#34; </span></span><span class="line"><span class="cl">&#34;output&#34; </span></span><span class="line"><span class="cl">&#34;x&#34; </span></span><span class="line"><span class="cl">-&#34;y&#34; </span></span><span class="line"><span class="cl">--&#34;z&#34; </span></span><span class="line"><span class="cl">&#34;example&#34; </span></span><span class="line"><span class="cl">&#34;a&#34; </span></span><span class="line"><span class="cl">-&#34;b&#34; </span></span><span class="line"><span class="cl">--&#34;c&#34; </span></span></code></pre></div><h3 id="7-creating-and-using-a-temporary-directory"> 7. Creating and Using a Temporary Directory <a class="hash-link" href="#7-creating-and-using-a-temporary-directory" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Thus far, I have used the current directory to create new files and test dirs, but the <code>std::filesystem</code> library provides facilities to create and manage temporary directories in a better way. It all comes down to the <code>temp_directory_path()</code> function:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">create_temp_file</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span><span class="o">&amp;</span> <span class="n">dir</span><span class="p">,</span> <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">filename</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">file_path</span> <span class="o">=</span> <span class="n">dir</span> <span class="o">/</span> <span class="n">filename</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;This is a temporary file.&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Temporary file created at: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">file_path</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">temp_dir</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">temp_directory_path</span><span class="p">()</span> <span class="o">/</span> <span class="s">&#34;my_temp_directory&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directory</span><span class="p">(</span><span class="n">temp_dir</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Temporary directory created at: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">temp_dir</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">create_temp_file</span><span class="p">(</span><span class="n">temp_dir</span><span class="p">,</span> <span class="s">&#34;temp_file.txt&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Contents of the temporary directory:</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">directory_iterator</span><span class="p">(</span><span class="n">temp_dir</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/e5WErK9Tc">@Compiler Explorer</a></p> <p>Possible output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Temporary directory created at: &#34;/tmp/my_temp_directory&#34; </span></span><span class="line"><span class="cl">Temporary file created at: &#34;/tmp/my_temp_directory/temp_file.txt&#34; </span></span><span class="line"><span class="cl">Contents of the temporary directory: </span></span><span class="line"><span class="cl">&#34;/tmp/my_temp_directory/temp_file.txt&#34; </span></span></code></pre></div><p>On Windows (Running and compiling from Visual Studio) I&rsquo;m getting the following output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Temporary directory created at: &#34;C:\\Users\\Admin\\AppData\\Local\\Temp\\my_temp_directory&#34; </span></span><span class="line"><span class="cl">Temporary file created at: &#34;C:\\Users\\Admin\\AppData\\Local\\Temp\\my_temp_directory\\temp_file.txt&#34; </span></span><span class="line"><span class="cl">Contents of the temporary directory: </span></span><span class="line"><span class="cl">&#34;C:\\Users\\Admin\\AppData\\Local\\Temp\\my_temp_directory\\temp_file.txt&#34; </span></span></code></pre></div><h2 id="file-operations"> File Operations <a class="hash-link" href="#file-operations" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <h3 id="7-copying-files"> 7. Copying Files <a class="hash-link" href="#7-copying-files" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Copying files is a common task, especially when working with backups or file distribution. Use the <code>copy</code> function to achieve this.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">src</span> <span class="o">=</span> <span class="s">&#34;source_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">dest</span> <span class="o">=</span> <span class="s">&#34;destination_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">copy</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">dest</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;File copied successfully</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">filesystem_error</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/1bszsY64v">@Compiler Explorer</a></p> <p>The code won&rsquo;t run, as we have no files:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">filesystem error: cannot copy: No such file or directory [source_file.txt] [destination_file.txt] </span></span></code></pre></div><h3 id="8-copying-files--recursively"> 8. Copying Files Recursively <a class="hash-link" href="#8-copying-files--recursively" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Copying directories, including their contents, can be done using the <code>copy</code> function with recursive options.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">create_temp_directories_and_files</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directories</span><span class="p">(</span><span class="s">&#34;source_directory/subdir1&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directories</span><span class="p">(</span><span class="s">&#34;source_directory/subdir2&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="s">&#34;source_directory/file1.txt&#34;</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;This is file 1&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="s">&#34;source_directory/subdir1/file2.txt&#34;</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;This is file 2&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="s">&#34;source_directory/subdir2/file3.txt&#34;</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;This is file 3&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">create_temp_directories_and_files</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">src</span> <span class="o">=</span> <span class="s">&#34;source_directory&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">dest</span> <span class="o">=</span> <span class="s">&#34;destination_directory&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">copy</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">dest</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">copy_options</span><span class="o">::</span><span class="n">recursive</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Directory copied successfully</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">filesystem_error</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">recursive_directory_iterator</span><span class="p">(</span><span class="n">dest</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/KqdTznThz">@Compiler Explorer</a></p> <p>The interesting part is that there&rsquo;s a function overload which takes <code>std::filesystem::copy_options</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">enum</span> <span class="k">class</span> <span class="nc">copy_options</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">none</span> <span class="o">=</span> <span class="cm">/* unspecified */</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">skip_existing</span> <span class="o">=</span> <span class="cm">/* unspecified */</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">overwrite_existing</span> <span class="o">=</span> <span class="cm">/* unspecified */</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">update_existing</span> <span class="o">=</span> <span class="cm">/* unspecified */</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">recursive</span> <span class="o">=</span> <span class="cm">/* unspecified */</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">copy_symlinks</span> <span class="o">=</span> <span class="cm">/* unspecified */</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">skip_symlinks</span> <span class="o">=</span> <span class="cm">/* unspecified */</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">directories_only</span> <span class="o">=</span> <span class="cm">/* unspecified */</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">create_symlinks</span> <span class="o">=</span> <span class="cm">/* unspecified */</span><span class="p">,</span> </span></span><span class="line"><span class="cl"> <span class="n">create_hard_links</span> <span class="o">=</span> <span class="cm">/* unspecified */</span> </span></span><span class="line"><span class="cl"><span class="p">};</span> </span></span></code></pre></div><p>See more examples <a href="https://en.cppreference.com/w/cpp/filesystem/copy_options">@CppReference</a></p> <h3 id="9-moving-and-renaming-files"> 9. Moving and Renaming Files <a class="hash-link" href="#9-moving-and-renaming-files" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Moving and renaming files or directories can be done using the <code>rename</code> function.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">ls</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">directory_iterator</span><span class="p">(</span><span class="s">&#34;.&#34;</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="s">&#34;old_file.txt&#34;</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;This is file 1&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">old_name</span> <span class="o">=</span> <span class="s">&#34;old_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">new_name</span> <span class="o">=</span> <span class="s">&#34;new_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">ls</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">rename</span><span class="p">(</span><span class="n">old_name</span><span class="p">,</span> <span class="n">new_name</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;File renamed/moved successfully</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">ls</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">filesystem_error</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/KbrT1Eo8e">@Compiler Explorer</a></p> <h3 id="10-creating-hard-links"> 10. Creating Hard Links <a class="hash-link" href="#10-creating-hard-links" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Hard links provide multiple directory entries for a single file. Use the <code>create_hard_link</code> function to create them.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;format&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">ls</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">directory_iterator</span><span class="p">(</span><span class="s">&#34;.&#34;</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&#34;{}, link count {}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">().</span><span class="n">c_str</span><span class="p">(),</span> <span class="n">entry</span><span class="p">.</span><span class="n">hard_link_count</span><span class="p">());</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="s">&#34;target_file.txt&#34;</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;This is file 1&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">target</span> <span class="o">=</span> <span class="s">&#34;target_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">link</span> <span class="o">=</span> <span class="s">&#34;hard_link_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_hard_link</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="n">link</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Hard link created successfully</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">ls</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">filesystem_error</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/vMz6fWzv1">@Compiler Explorer</a></p> <p>Possible output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Hard link created successfully </span></span><span class="line"><span class="cl">./compilation-result.json, link count 1 </span></span><span class="line"><span class="cl">./target_file.txt, link count 2 </span></span><span class="line"><span class="cl">./hard_link_file.txt, link count 2 </span></span><span class="line"><span class="cl">./output.s, link count 1 </span></span><span class="line"><span class="cl">./example.cpp, link count 1 </span></span></code></pre></div><h3 id="11-creating-symbolic-links"> 11. Creating Symbolic Links <a class="hash-link" href="#11-creating-symbolic-links" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Symbolic links (symlinks) are another way to reference files. Use the <code>create_symlink</code> function for this.</p> <p><a href="https://stackoverflow.com/questions/185899/what-is-the-difference-between-a-symbolic-link-and-a-hard-link">unix - What is the difference between a symbolic link and a hard link? - Stack Overflow</a></p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">display_file_content</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span><span class="o">&amp;</span> <span class="n">path</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">exists</span><span class="p">(</span><span class="n">path</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ifstream</span> <span class="n">file</span><span class="p">(</span><span class="n">path</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">content</span><span class="p">((</span><span class="n">std</span><span class="o">::</span><span class="n">istreambuf_iterator</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">(</span><span class="n">file</span><span class="p">)),</span> <span class="n">std</span><span class="o">::</span><span class="n">istreambuf_iterator</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Content of &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">path</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">content</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">path</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; does not exist.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">original_file</span> <span class="o">=</span> <span class="s">&#34;original_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">symlink</span> <span class="o">=</span> <span class="s">&#34;symlink_to_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">hardlink</span> <span class="o">=</span> <span class="s">&#34;hardlink_to_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Step 1: Create the original file </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="n">original_file</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Hello World!&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Original file created.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">display_file_content</span><span class="p">(</span><span class="n">original_file</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Step 2: Create a symbolic link to the original file </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_symlink</span><span class="p">(</span><span class="n">original_file</span><span class="p">,</span> <span class="n">symlink</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Symbolic link created successfully.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">display_file_content</span><span class="p">(</span><span class="n">symlink</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">filesystem_error</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Step 3: Create a hard link to the original file </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_hard_link</span><span class="p">(</span><span class="n">original_file</span><span class="p">,</span> <span class="n">hardlink</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Hard link created successfully.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">display_file_content</span><span class="p">(</span><span class="n">hardlink</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">filesystem_error</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Step 4: Delete the original file and compare... </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">remove</span><span class="p">(</span><span class="n">original_file</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Original file deleted.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">display_file_content</span><span class="p">(</span><span class="n">symlink</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">display_file_content</span><span class="p">(</span><span class="n">hardlink</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/13h6xG4c3">@Compiler Explorer</a></p> <p>Possible output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Original file created. </span></span><span class="line"><span class="cl">Content of &#34;original_file.txt&#34;: Hello World! </span></span><span class="line"><span class="cl">Symbolic link created successfully. </span></span><span class="line"><span class="cl">Content of &#34;symlink_to_file.txt&#34;: Hello World! </span></span><span class="line"><span class="cl">Hard link created successfully. </span></span><span class="line"><span class="cl">Content of &#34;hardlink_to_file.txt&#34;: Hello World! </span></span><span class="line"><span class="cl">Original file deleted. </span></span><span class="line"><span class="cl">&#34;symlink_to_file.txt&#34; does not exist. </span></span><span class="line"><span class="cl">Content of &#34;hardlink_to_file.txt&#34;: Hello World! </span></span></code></pre></div><h2 id="path-and-existence-checks"> Path and Existence Checks <a class="hash-link" href="#path-and-existence-checks" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <h3 id="12-checking-file-or-directory-existence"> 12. Checking File or Directory Existence <a class="hash-link" href="#12-checking-file-or-directory-existence" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Before performing operations on files or directories, it’s often necessary to check their existence using the <code>exists</code> function.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">p</span> <span class="o">=</span> <span class="s">&#34;example_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">exists</span><span class="p">(</span><span class="n">p</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;File or directory exists</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;File or directory does not exist</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/vE1c1Wozo">@Compiler Explorer</a></p> <h3 id="13-checking-if-a-path-is-a-file-or-directory"> 13. Checking if a Path is a File or Directory <a class="hash-link" href="#13-checking-if-a-path-is-a-file-or-directory" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Differentiating between files and directories is crucial for many file processing tasks. The <code>is_regular_file</code> and <code>is_directory</code> functions help with this.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">p</span> <span class="o">=</span> <span class="s">&#34;example_path&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">is_regular_file</span><span class="p">(</span><span class="n">p</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;It&#39;s a file</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">is_directory</span><span class="p">(</span><span class="n">p</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;It&#39;s a directory</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">else</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;It&#39;s neither a regular file nor a directory</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/7YoM7dvca">@Compiler Explorer</a></p> <h3 id="14-reading-symlink-status"> 14. Reading Symlink Status <a class="hash-link" href="#14-reading-symlink-status" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>If your application deals with symbolic links, you may need to read the status of these links using the <code>is_symlink</code> function. To get the target file, you can use <code>read_symlink()</code>:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">original_file</span> <span class="o">=</span> <span class="s">&#34;original_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">symlink</span> <span class="o">=</span> <span class="s">&#34;symlink_to_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="n">original_file</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Hello World!&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Original file created.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_symlink</span><span class="p">(</span><span class="n">original_file</span><span class="p">,</span> <span class="n">symlink</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Symbolic link created successfully.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">filesystem_error</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">is_symlink</span><span class="p">(</span><span class="n">symlink</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">symlink</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; is a symbolic link.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">target</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">read_symlink</span><span class="p">(</span><span class="n">symlink</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;It points to: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">target</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">symlink</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; is not a symbolic link.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/TMvMPjMjv">@Compiler Explorer</a></p> <h3 id="15-getting-absolute-path"> 15. Getting Absolute Path <a class="hash-link" href="#15-getting-absolute-path" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Getting the absolute path of a relative path is often necessary for various file operations. Use the <code>absolute</code> function for this.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Example relative paths </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">relative_path1</span> <span class="o">=</span> <span class="s">&#34;example_directory&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">relative_path2</span> <span class="o">=</span> <span class="s">&#34;../parent_directory&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">relative_path3</span> <span class="o">=</span> <span class="s">&#34;subdir/another_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Convert to absolute paths </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">absolute_path1</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">absolute</span><span class="p">(</span><span class="n">relative_path1</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">absolute_path2</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">absolute</span><span class="p">(</span><span class="n">relative_path2</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">absolute_path3</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">absolute</span><span class="p">(</span><span class="n">relative_path3</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Display the absolute paths </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Relative path: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">relative_path1</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; -&gt; Absolute path: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">absolute_path1</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Relative path: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">relative_path2</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; -&gt; Absolute path: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">absolute_path2</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Relative path: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">relative_path3</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; -&gt; Absolute path: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">absolute_path3</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/1MeE4MP35">@Compiler Explorer</a></p> <p>Possible output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Relative path: &#34;example_directory&#34; -&gt; Absolute path: &#34;/app/example_directory&#34; </span></span><span class="line"><span class="cl">Relative path: &#34;../parent_directory&#34; -&gt; Absolute path: &#34;/app/../parent_directory&#34; </span></span><span class="line"><span class="cl">Relative path: &#34;subdir/another_file.txt&#34; -&gt; Absolute path: &#34;/app/subdir/another_file.txt&#34; </span></span></code></pre></div><h3 id="16-getting-relative-path"> 16. Getting Relative Path <a class="hash-link" href="#16-getting-relative-path" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Sometimes, you need to convert an absolute path to a relative path. The <code>relative</code> function can be used for this purpose.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">base_path</span> <span class="o">=</span> <span class="s">&#34;/home/user&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">absolute_path</span> <span class="o">=</span> <span class="s">&#34;/home/user/example_directory/file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">relative_path</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">relative</span><span class="p">(</span><span class="n">absolute_path</span><span class="p">,</span> <span class="n">base_path</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Relative path: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">relative_path</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/snxznvfob">@Compiler Explorer</a></p> <h3 id="17-displaying-paths-without-quotes"> 17. Displaying paths without quotes <a class="hash-link" href="#17-displaying-paths-without-quotes" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Have you noticed that when I print out a path object, it always has quotes around it?</p> <p>According to <a href="https://en.cppreference.com/w/cpp/filesystem/path/operator_ltltgtgt">CppReference</a> the stream operator for the <code>path</code> class is defined in the following way:</p> <blockquote> <p>Performs stream input or output on the path p. <code>std::quoted</code> is used so that spaces do not cause truncation when later read by stream input operator.</p> </blockquote> <p>To remove the quotes, we just need to get the raw string that represents the path. For example:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">ls</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">directory_iterator</span><span class="p">(</span><span class="s">&#34;.&#34;</span><span class="p">))</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">().</span><span class="n">c_str</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>So the output can be:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">./compilation-result.json </span></span><span class="line"><span class="cl">./output.s </span></span><span class="line"><span class="cl">./example.cpp </span></span></code></pre></div><p>Rather than:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&#34;./compilation-result.json&#34; </span></span><span class="line"><span class="cl">&#34;./output.s&#34; </span></span><span class="line"><span class="cl">&#34;./example.cpp&#34; </span></span></code></pre></div><h2 id="miscellaneous-operations"> Miscellaneous Operations <a class="hash-link" href="#miscellaneous-operations" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <h3 id="18-calculating-directory-size"> 18. Calculating Directory Size <a class="hash-link" href="#18-calculating-directory-size" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Calculating the total size of all files within a directory can be useful for disk usage analysis and cleanup tasks.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="c1">// Function to create a test directory with some files and subdirectories </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">void</span> <span class="nf">create_test_directory</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span><span class="o">&amp;</span> <span class="n">dir</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directories</span><span class="p">(</span><span class="n">dir</span> <span class="o">/</span> <span class="s">&#34;subdir1&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">create_directories</span><span class="p">(</span><span class="n">dir</span> <span class="o">/</span> <span class="s">&#34;subdir2&#34;</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="n">dir</span> <span class="o">/</span> <span class="s">&#34;file1.txt&#34;</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;ABC&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="n">dir</span> <span class="o">/</span> <span class="s">&#34;subdir1/file2.txt&#34;</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;XYZ&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="n">dir</span> <span class="o">/</span> <span class="s">&#34;subdir2/file3.txt&#34;</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;123&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="c1">// Function to calculate the total size of a directory </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">uintmax_t</span> <span class="n">calculate_directory_size</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span><span class="o">&amp;</span> <span class="n">dir</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">uintmax_t</span> <span class="n">size</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">recursive_directory_iterator</span><span class="p">(</span><span class="n">dir</span><span class="p">))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">is_regular_file</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">()))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">size</span> <span class="o">+=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">file_size</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">size</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="c1">// Create a test directory with some files and subdirectories </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">test_dir</span> <span class="o">=</span> <span class="s">&#34;test_directory&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">create_test_directory</span><span class="p">(</span><span class="n">test_dir</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Test directory created.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Calculate the total size of the test directory </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">uintmax_t</span> <span class="n">total_size</span> <span class="o">=</span> <span class="n">calculate_directory_size</span><span class="p">(</span><span class="n">test_dir</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Total size of directory &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">test_dir</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">total_size</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; bytes</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Clean up by removing the test directory and its contents </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">remove_all</span><span class="p">(</span><span class="n">test_dir</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Test directory removed.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/5oYTr4rYx">@Compiler Explorer</a></p> <p>Do you know what the size of that test directory will be?</p> <h3 id="19-determining-free-space-on-a-filesystem"> 19. Determining Free Space on a Filesystem <a class="hash-link" href="#19-determining-free-space-on-a-filesystem" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Knowing the available free space on a filesystem is important for managing storage and preventing errors due to insufficient disk space. The <code>space()</code> function returns a <code>space_info</code> object that contains information about the free space, available space, and capacity of the filesystem where a given path is located.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">p</span> <span class="o">=</span> <span class="s">&#34;/&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="k">auto</span> <span class="n">space_info</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">space</span><span class="p">(</span><span class="n">p</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Free space: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">space_info</span><span class="p">.</span><span class="n">free</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; bytes</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Available space: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">space_info</span><span class="p">.</span><span class="n">available</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; bytes</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Capacity: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">space_info</span><span class="p">.</span><span class="n">capacity</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; bytes</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/veMzxMKMY">@Compiler Explorer</a></p> <h3 id="20-checking-file-permissions"> 20. Checking File Permissions <a class="hash-link" href="#20-checking-file-permissions" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>File permissions determine who can read, write, or execute a file. Use the <code>status</code> function to check these permissions.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">file</span> <span class="o">=</span> <span class="s">&#34;example_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span> <span class="n">p</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">status</span><span class="p">(</span><span class="n">file</span><span class="p">).</span><span class="n">permissions</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Permissions for &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">file</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;:</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">owner_read</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;r&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">owner_write</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;w&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">owner_exec</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;x&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/9Wscd97Go">@Compiler Explorer</a></p> <h3 id="21-setting-file-permissions"> 21. Setting File Permissions <a class="hash-link" href="#21-setting-file-permissions" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Changing file permissions can be necessary for securing files or enabling certain operations. Use the <code>permissions</code> function to set these permissions.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">create_test_file</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span><span class="o">&amp;</span> <span class="n">path</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;This is a test file.&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Test file created at: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">path</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">display_permissions</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span><span class="o">&amp;</span> <span class="n">path</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span> <span class="n">p</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">status</span><span class="p">(</span><span class="n">path</span><span class="p">).</span><span class="n">permissions</span><span class="p">();</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Permissions for &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">path</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;: &#34;</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">owner_read</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;r&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">owner_write</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;w&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">owner_exec</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;x&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">group_read</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;r&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">group_write</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;w&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">group_exec</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;x&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">others_read</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;r&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">others_write</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;w&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="p">((</span><span class="n">p</span> <span class="o">&amp;</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">others_exec</span><span class="p">)</span> <span class="o">!=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">none</span> <span class="o">?</span> <span class="s">&#34;x&#34;</span> <span class="o">:</span> <span class="s">&#34;-&#34;</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">path</span> <span class="n">test_file</span> <span class="o">=</span> <span class="s">&#34;test_file.txt&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">create_test_file</span><span class="p">(</span><span class="n">test_file</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Initial &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">display_permissions</span><span class="p">(</span><span class="n">test_file</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// Set new permissions for the test file </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span> <span class="n">new_perms</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">owner_read</span> <span class="o">|</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">owner_write</span> <span class="o">|</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">perms</span><span class="o">::</span><span class="n">owner_exec</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">try</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">permissions</span><span class="p">(</span><span class="n">test_file</span><span class="p">,</span> <span class="n">new_perms</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Permissions changed successfully</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">filesystem_error</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Updated &#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">display_permissions</span><span class="p">(</span><span class="n">test_file</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="o">::</span><span class="n">remove</span><span class="p">(</span><span class="n">test_file</span><span class="p">);</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Test file removed.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/1zedqKPEa">@Compiler Explorer</a></p> <p>Possible output:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Test file created at: &#34;test_file.txt&#34; </span></span><span class="line"><span class="cl">Initial Permissions for &#34;test_file.txt&#34;: rw-rw-r-- </span></span><span class="line"><span class="cl">Permissions changed successfully </span></span><span class="line"><span class="cl">Updated Permissions for &#34;test_file.txt&#34;: rwx------ </span></span><span class="line"><span class="cl">Test file removed. </span></span></code></pre></div><h3 id="22-listing-files-in-last-modification-time-order"> 22. Listing Files in Last Modification Time Order <a class="hash-link" href="#22-listing-files-in-last-modification-time-order" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h3> <p>Sorting and listing files based on their last modification time can be useful for many applications, such as finding the most recently modified files. The following example demonstrates how to list files in a directory sorted by their last modification time.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;filesystem&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;format&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;map&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;chrono&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;thread&gt;</span><span class="cp"> </span></span></span><span class="line"><span class="cl"><span class="cp"></span> </span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="n">fs</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">filesystem</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">map</span><span class="o">&lt;</span><span class="n">fs</span><span class="o">::</span><span class="n">file_time_type</span><span class="p">,</span> <span class="n">fs</span><span class="o">::</span><span class="n">path</span><span class="o">&gt;</span> <span class="n">files</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">fs</span><span class="o">::</span><span class="n">path</span><span class="o">&gt;</span> <span class="n">toDelete</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="c1">// create some files... </span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="n">toDelete</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&#34;example{}.txt&#34;</span><span class="p">,</span> <span class="n">i</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">ofstream</span><span class="p">(</span><span class="n">toDelete</span><span class="p">.</span><span class="n">back</span><span class="p">().</span><span class="n">c_str</span><span class="p">())</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Hello, World!&#34;</span><span class="p">;</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep_for</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">seconds</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">entry</span> <span class="p">:</span> <span class="n">fs</span><span class="o">::</span><span class="n">directory_iterator</span><span class="p">(</span><span class="n">fs</span><span class="o">::</span><span class="n">current_path</span><span class="p">()))</span> <span class="p">{</span> </span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">is_regular_file</span><span class="p">())</span> </span></span><span class="line"><span class="cl"> <span class="n">files</span><span class="p">.</span><span class="n">emplace</span><span class="p">(</span><span class="n">fs</span><span class="o">::</span><span class="n">last_write_time</span><span class="p">(</span><span class="n">entry</span><span class="p">),</span> <span class="n">entry</span><span class="p">.</span><span class="n">path</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> <span class="p">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="p">[</span><span class="n">time</span><span class="p">,</span> <span class="n">path</span><span class="p">]</span> <span class="o">:</span> <span class="n">files</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&#34;{0:%X} on {0:%F}, {1}</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">time</span><span class="p">,</span> <span class="n">path</span><span class="p">.</span><span class="n">string</span><span class="p">());</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="nl">f</span> <span class="p">:</span> <span class="n">toDelete</span><span class="p">)</span> </span></span><span class="line"><span class="cl"> <span class="n">fs</span><span class="o">::</span><span class="n">remove</span><span class="p">(</span><span class="n">f</span><span class="p">);</span> </span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div><p>Run <a href="https://godbolt.org/z/Yd4hdcczc">@Compiler Explorer</a></p> <h2 id="summary"> Summary <a class="hash-link" href="#summary" aria-hidden="true"> <svg class="fill-current o-60 hover-accent-color-light" height="24" viewBox="0 0 24 24" width="22" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76.0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71.0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71.0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76.0 5-2.24 5-5s-2.24-5-5-5z"></path></svg> </a>&nbsp; </h2> <p>In this blog post, we&rsquo;ve explored a variety of essential filesystem operations using the <code>std::filesystem</code> library in C++17, C++20, and C++23. From creating directories and files to managing symbolic and hard links, and from checking file permissions to calculating directory sizes, we&rsquo;ve covered the fundamental tasks you need to handle the filesystem efficiently.</p> <p>I hope this guide has provided you with valuable insights and practical examples to help you navigate the complexities of filesystem operations in C++.</p> <h4 id="back-to-you"> Back to you </h4> <ul> <li>Do you use <code>std::filesystem</code>?</li> <li>What other operations are useful when working with the filesystem?</li> </ul> <p>Share your comment below.</p>