{"id":6378,"date":"2022-06-09T20:20:34","date_gmt":"2022-06-09T20:20:34","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/improved-iterators-with-ranges\/"},"modified":"2023-09-27T16:49:52","modified_gmt":"2023-09-27T16:49:52","slug":"improved-iterators-with-ranges","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/improved-iterators-with-ranges\/","title":{"rendered":"Improved Iterators with Ranges"},"content":{"rendered":"<p>There are more reasons to prefer ranges library above the classical Standard Template Library. The ranges iterators support unified lookup rules and provide additional safety guarantees.<\/p>\n<p><!--more--><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8380 size-full\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/TimelineCpp20Ranges.png\" alt=\"\" width=\"979\" height=\"373\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/TimelineCpp20Ranges.png 979w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/TimelineCpp20Ranges-300x114.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/TimelineCpp20Ranges-768x293.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/TimelineCpp20Ranges-705x269.png 705w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/TimelineCpp20Ranges-845x321.png 845w\" sizes=\"auto, (max-width: 979px) 100vw, 979px\" \/><\/p>\n<h2>Unified Lookup Rules<\/h2>\n<p>Assume you want to implement a generic function that calls <code>begin<\/code> on a given container. The question is if the function calling <code>begin<\/code> on a container should assume a free <code>begin<\/code> function or a member function <code>begin<\/code>?<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ begin.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;cstddef&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;ranges&gt;<\/span>\n\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> ContainerFree {                                        <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n    ContainerFree(std<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">size_t<\/span> len)<span style=\"color: #555555;\">:<\/span> len_(len), data_(<span style=\"color: #006699; font-weight: bold;\">new<\/span> <span style=\"color: #007788; font-weight: bold;\">int<\/span>[len]){}\n    <span style=\"color: #007788; font-weight: bold;\">size_t<\/span> len_;\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">*<\/span> data_;\n};\n<span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">*<\/span> <span style=\"color: #cc00ff;\">begin<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> ContainerFree<span style=\"color: #555555;\">&amp;<\/span> conFree) {                   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> conFree.data_;\n}\n\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> ContainerMember {                                     <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\n    ContainerMember(std<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">size_t<\/span> len)<span style=\"color: #555555;\">:<\/span> len_(len), data_(<span style=\"color: #006699; font-weight: bold;\">new<\/span> <span style=\"color: #007788; font-weight: bold;\">int<\/span>[len]){}\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">*<\/span> begin() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {                                     <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> data_;\n    }\n    <span style=\"color: #007788; font-weight: bold;\">size_t<\/span> len_;\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">*<\/span> data_;\n};\n\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">callBeginFree<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> cont) {                        <span style=\"color: #0099ff; font-style: italic;\">\/\/ (5)<\/span>\n    begin(cont);\n}\n\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">callBeginMember<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> cont) {                      <span style=\"color: #0099ff; font-style: italic;\">\/\/ (6)<\/span>\n    cont.begin();\n}\n \n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\n\n    <span style=\"color: #006699; font-weight: bold;\">const<\/span> ContainerFree contFree(<span style=\"color: #ff6600;\">2020<\/span>);\n    <span style=\"color: #006699; font-weight: bold;\">const<\/span> ContainerMember contMemb(<span style=\"color: #ff6600;\">2023<\/span>);\n\n    callBeginFree(contFree);                                 \n    callBeginMember(contMemb);\n\n    callBeginFree(contMemb);                                  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (7)<\/span>\n    callBeginMember(contFree);                                <span style=\"color: #0099ff; font-style: italic;\">\/\/ (8)<\/span>\n   \n}\n<\/pre>\n<\/div>\n<div>\n<div><code>ContainerFree<\/code> (line 1) has a free function <code>begin<\/code> (line 2), and <code>ContainerMember<\/code> (line 3) has a member function <code>begin<\/code> (line 4). Accordingly, <code>contFree<\/code> can use the generic function <code>callBeginFree<\/code> using the free function call <code>begin(cont)<\/code> (line 5), and <code>contMemb<\/code> can use the generic function <code>callBeginMember<\/code> using the member function call<code> cont.begin<\/code> (line 6). When I invoke <code>callBeginFree<\/code> and <code>callBeginMember<\/code> The compilation fails with the inappropriate containers in lines (7) and (8).<\/div>\n<div><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6374\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/begin.png\" alt=\"begin\" width=\"650\" height=\"238\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/begin.png 1173w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/begin-300x110.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/begin-1024x375.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/begin-768x282.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/div>\n<\/div>\n<p>I can solve this issue by providing two different <code>begin<\/code> implementations: classical and range based.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ beginSolved.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;cstddef&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;ranges&gt;<\/span>\n\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> ContainerFree {\n    ContainerFree(std<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">size_t<\/span> len)<span style=\"color: #555555;\">:<\/span> len_(len), data_(<span style=\"color: #006699; font-weight: bold;\">new<\/span> <span style=\"color: #007788; font-weight: bold;\">int<\/span>[len]){}\n    <span style=\"color: #007788; font-weight: bold;\">size_t<\/span> len_;\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">*<\/span> data_;\n};\n<span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">*<\/span> <span style=\"color: #cc00ff;\">begin<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> ContainerFree<span style=\"color: #555555;\">&amp;<\/span> conFree) {\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> conFree.data_;\n}\n\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> ContainerMember {\n    ContainerMember(std<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">size_t<\/span> len)<span style=\"color: #555555;\">:<\/span> len_(len), data_(<span style=\"color: #006699; font-weight: bold;\">new<\/span> <span style=\"color: #007788; font-weight: bold;\">int<\/span>[len]){}\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">*<\/span> begin() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> data_;\n    }\n    <span style=\"color: #007788; font-weight: bold;\">size_t<\/span> len_;\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">*<\/span> data_;\n};\n\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">callBeginClassical<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> cont) {\n    <span style=\"color: #006699; font-weight: bold;\">using<\/span> std<span style=\"color: #555555;\">::<\/span>begin;                          <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n    begin(cont);\n}\n\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">callBeginRanges<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> cont) {\n    std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>begin(cont);                  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\n}\n \n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\n\n    <span style=\"color: #006699; font-weight: bold;\">const<\/span> ContainerFree contFree(<span style=\"color: #ff6600;\">2020<\/span>);\n    <span style=\"color: #006699; font-weight: bold;\">const<\/span> ContainerMember contMemb(<span style=\"color: #ff6600;\">2023<\/span>);\n\n    callBeginClassical(contFree);\n    callBeginRanges(contMemb);\n\n    callBeginClassical(contMemb);\n    callBeginRanges(contFree);\n   \n}\n<\/pre>\n<\/div>\n<p>The classical way to solve this issue is to bring<code> std::begin<\/code> into the scope with a so-called using-declaration (line 1). Thanks to ranges, you can directly use <code>std::ranges::begin<\/code> (line 2).<code> std::ranges::begin<\/code> considers both implementations of <code>begin<\/code>: the free version and the member function.<\/p>\n<p>Finally, let me write about safety.<\/p>\n<h2>Safety<\/h2>\n<p>Let me start with iterators.<\/p>\n<h3>Iterators<\/h3>\n<div>\n<div>The ranges library provides the expected operations to access the range.<\/div>\n<div><\/div>\n<div>\u00a0<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6375\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/iterators.jpg\" alt=\"iterators\" width=\"650\" height=\"640\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/iterators.jpg 727w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/iterators-300x295.jpg 300w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/div>\n<\/div>\n<p>There is a big difference when you use these operations for accessing the underlying range. The compilation fails when you use the range access on the <code>std::ranges<\/code>&#8216;s variant if the argument is an rvalue. On the contrary, using the same operation from the classical <code>std<\/code> namespace is undefined behavior.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ rangesAccess.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;iterator&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;ranges&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\n\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> beginIt1 <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>begin(std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span>{<span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">2<\/span>, <span style=\"color: #ff6600;\">3<\/span>});\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> beginIt2 <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>begin(std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span>{<span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">2<\/span>, <span style=\"color: #ff6600;\">3<\/span>});\n\n}\n<\/pre>\n<\/div>\n<p><code>std::ranges::begin<\/code> provides only overloads for lvalues. The temporary vector<code> std::vector{1, 2, 3}<\/code> is an rvalue. Consequentially, the compilation of the program fails.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6376\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/rangeAccessError.png\" alt=\"rangeAccessError\" width=\"650\" height=\"451\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/rangeAccessError.png 1146w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/rangeAccessError-300x208.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/rangeAccessError-1024x710.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/rangeAccessError-768x533.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p>The abbreviations lvalue and rvalue stand for locatable value and readable value.<\/p>\n<ul>\n<li>lvalue (locatable value): A locatable value is an object with a location in memory, and you can, therefore, determine its address. An lvalue has an identity.<\/li>\n<li>rvalue (readable value): A rvalue is a value you can only read from. It does not represent an object in memory, and you cannot determine its address.<\/li>\n<\/ul>\n<p>I must admit that my short explanations of lvalues and rvalues are a simplification. If you want more details about value categories, read the following post,<a href=\"https:\/\/devtut.github.io\/cpp\/value-categories.html\"> Value Categories<\/a>.<\/p>\n<p>By the way, iterators and views provide these additional safety guarantees.<\/p>\n<h3>Views<\/h3>\n<p>Views do not own data. Therefore, views do not extend the lifetime of their data. Consequently, views can only be created on lvalues. The compilation fails if you create a view on a temporary range.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0px; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ temporaryRange.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;initializer_list&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;ranges&gt;<\/span>\n\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\n\n    <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #006699; font-weight: bold;\">auto<\/span> numbers <span style=\"color: #555555;\">=<\/span> {<span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">2<\/span>, <span style=\"color: #ff6600;\">3<\/span>, <span style=\"color: #ff6600;\">4<\/span>, <span style=\"color: #ff6600;\">5<\/span>};\n\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> firstThree <span style=\"color: #555555;\">=<\/span> numbers <span style=\"color: #555555;\">|<\/span> std<span style=\"color: #555555;\">::<\/span>views<span style=\"color: #555555;\">::<\/span>drop(<span style=\"color: #ff6600;\">3<\/span>);           <em>  <span style=\"color: #0099ff;\">\/\/ (1)<\/span><\/em>\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ auto firstThree = {1, 2, 3, 4, 5} | std::views::drop(3);  \/\/ (2)<\/span>\n\n    std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>drop_view firstFour{numbers, <span style=\"color: #ff6600;\">4<\/span>};             <em>   <span style=\"color: #0099ff;\">\/\/ (3)<\/span><\/em>\n   <span style=\"color: #0099ff; font-style: italic;\">\/\/ std::ranges::drop_view firstFour{{1, 2, 3, 4, 5}, 4};      \/\/ (4)<\/span>\n   \n}\n<\/pre>\n<\/div>\n<p>All is fine when lines 1 and 3 are used with the lvalue numbers. On the contrary, using the commented-out lines 2 and 4 on the rvalue<code> std::initializer_list&lt;int&gt; {1, 2, 3, 4, 5}<\/code>, causes the GCC compiler to complain verbosely:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6377\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/temporaryRange.png\" alt=\"temporaryRange\" width=\"650\" height=\"288\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/temporaryRange.png 1862w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/temporaryRange-300x133.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/temporaryRange-1024x453.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/temporaryRange-768x340.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/06\/temporaryRange-1536x680.png 1536w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>In my next post, I will first peek into the C++23 future. In particular, the ranges library will get many improvements. There is with <code>std::ranges::to<\/code> a convenient way to construct containers from ranges. Additionally, we will get almost twenty new algorithms. Here are a few of them:<code> std::views::chunk_by, std::views::slide, std::views::join_with, std::views::zip_transform,<\/code> and <code>std::views::adjacent_transform<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are more reasons to prefer ranges library above the classical Standard Template Library. The ranges iterators support unified lookup rules and provide additional safety guarantees.<\/p>\n","protected":false},"author":21,"featured_media":8380,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[414,413],"class_list":["post-6378","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-iterator","tag-ranges"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6378","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=6378"}],"version-history":[{"count":2,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6378\/revisions"}],"predecessor-version":[{"id":8382,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6378\/revisions\/8382"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/8380"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=6378"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=6378"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=6378"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}