{"id":2089,"date":"2022-01-23T12:26:14","date_gmt":"2022-01-23T11:26:14","guid":{"rendered":"https:\/\/www.nuonsoft.com\/blog\/?p=2089"},"modified":"2022-01-23T12:26:16","modified_gmt":"2022-01-23T11:26:16","slug":"c20-stdspan-a-view-on-a-continuous-sequence-of-data","status":"publish","type":"post","link":"https:\/\/www.nuonsoft.com\/blog\/2022\/01\/23\/c20-stdspan-a-view-on-a-continuous-sequence-of-data\/","title":{"rendered":"C++20: std::span &#8211; A View on a Continuous Sequence of Data"},"content":{"rendered":"\n<p><strong><a href=\"https:\/\/en.cppreference.com\/w\/cpp\/container\/span\" target=\"_blank\" rel=\"noreferrer noopener\">std::span<\/a><\/strong>, defined in <strong>&lt;span&gt;<\/strong>, allows you to handle a sequence of continuous data, without having to worry about where the data is actually stored. For example, suppose you have a function to print the elements of a <strong>std::vector<\/strong>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; quick-code: false; notranslate\" title=\"\">\nvoid print(const std::vector&lt;int&gt;&amp; values)\n{\n    for (const auto&amp; value : values) { std::cout &lt;&lt; value &lt;&lt; &quot; &quot;; }\n    std::cout &lt;&lt; std::endl;\n}\n<\/pre><\/div>\n\n\n<p>This function requires as argument a reference to a <strong>std::vector&lt;int&gt;<\/strong>. If you also want to print elements of a C-style array, then you can add a second overload of the <strong>print()<\/strong> function, for example:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; quick-code: false; notranslate\" title=\"\">\nvoid print(const int values&#x5B;], size_t count)\n{\n    for (size_t i{ 0 }; i &lt; count; ++i) { std::cout &lt;&lt; values&#x5B;i] &lt;&lt; &quot; &quot;; }\n    std::cout &lt;&lt; std::endl;\n}\n<\/pre><\/div>\n\n\n<p>With these two overloads, you can call your <strong>print()<\/strong> function with either a reference to a <strong>std::vector&lt;int&gt;<\/strong> or with a C-style array. If you want to support other containers, then you can add even more overloads. With <strong>std::span<\/strong>, it is possible to write a single function that can work with all kinds of sequential data. Instead of the previous two overloads, you can just write the following single function:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; quick-code: false; notranslate\" title=\"\">\nvoid print(std::span&lt;const int&gt; values)\n{\n    for (const auto&amp; value : values) { std::cout &lt;&lt; value &lt;&lt; &quot; &quot;; }\n    std::cout &lt;&lt; std::endl;\n}\n<\/pre><\/div>\n\n\n<p>Note that a <strong>span<\/strong> basically just contains a pointer to the first element in the sequence and the number of elements in the sequence, and never copies the underlying data. Hence, a <strong>span<\/strong> is very cheap to copy and is usually passed by value, just as <strong>std::string_view<\/strong>.<\/p>\n\n\n\n<p>This single <strong>print()<\/strong> function accepting a <strong>std::span<\/strong> can be called for continuous data stored in <strong>std::vector<\/strong>s, <strong>std::array<\/strong>s, C-style arrays, and more. Here are some examples:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; quick-code: false; notranslate\" title=\"\">\nstd::vector v{ 1, 2, 3 };\nprint(v);                   \/\/ Pass a vector.\n\nstd::array a{ 4, 5, 6, 7 };\nprint(a);                   \/\/ Pass a std::array.\nprint({ a.data() + 1, 2 }); \/\/ Pass part of a std::array.\n\nint ca&#x5B;]{ 8, 9, 10 };\nprint(ca);                  \/\/ Pass a C-style array.\n\nstd::span s{ v };           \/\/ Construct a span from a vector.\nprint(s);                   \/\/ Pass a std::span.\nprint(s.subspan(1, 2));     \/\/ Pass part of a std::span.\n<\/pre><\/div>\n\n\n<p>The output of this code snippet is as follows:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; quick-code: false; notranslate\" title=\"\">\n1 2 3\n4 5 6 7\n5 6\n8 9 10\n1 2 3\n2 3\n<\/pre><\/div>\n\n\n<hr class=\"wp-block-separator has-text-color has-background has-luminous-vivid-amber-background-color has-luminous-vivid-amber-color\"\/>\n\n\n\n<p><em><strong><span style=\"color:#009e00\" class=\"has-inline-color\">Tip:<\/span><\/strong> If you write a function accepting a <strong>const vector&lt;T&gt;&amp;<\/strong>, I recommend considering to accept a <strong>span&lt;const T&gt;<\/strong> instead. This allows your function to work with all kinds of continuous data, independent of where the data is actually stored.<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-text-color has-background has-luminous-vivid-amber-background-color has-luminous-vivid-amber-color\"\/>\n\n\n\n<p>My book,&nbsp;<a href=\"https:\/\/amzn.to\/2ZDHCCu\" target=\"_blank\" rel=\"noreferrer noopener\">Professional C++, 5th Edition<\/a>, explains all new C++20 features, and much more.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>std::span, defined in &lt;span&gt;, allows you to handle a sequence of continuous data, without having to worry about where the data is actually stored. For example, suppose you have a function to print the elements of a std::vector: This function requires as argument a reference to a std::vector&lt;int&gt;. If you also want to print elements [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[242,245],"class_list":["post-2089","post","type-post","status-publish","format-standard","hentry","category-c","tag-c20","tag-span"],"_links":{"self":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts\/2089","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/comments?post=2089"}],"version-history":[{"count":8,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts\/2089\/revisions"}],"predecessor-version":[{"id":2097,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts\/2089\/revisions\/2097"}],"wp:attachment":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/media?parent=2089"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/categories?post=2089"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/tags?post=2089"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}