{"id":6364,"date":"2022-05-25T05:47:29","date_gmt":"2022-05-25T05:47:29","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/projections-with-ranges\/"},"modified":"2023-09-27T16:57:36","modified_gmt":"2023-09-27T16:57:36","slug":"projections-with-ranges","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/projections-with-ranges\/","title":{"rendered":"Projections with Ranges"},"content":{"rendered":"<p>The algorithms of the ranges library are lazy, can work directly on the container, and can easily be composed. But they have more to offer: projections. A projection is a mapping of a set into a subset. Let me show you in this post what that means:<\/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<p>I ended my last post, &#8220;<a href=\"https:\/\/www.modernescpp.com\/index.php\/the-ranges-library-in-c-20-a-deep-dive\">The Ranges Libary in C++20: More Details<\/a>&#8221; with a comparison of<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/algorithm\/sort\"><code> std::sort<\/code><\/a> and <code>std::ranges::sort<\/code>. Here are the two overloads of <code>std::ranges::sort<\/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%;\"> \n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>random_access_iterator I, std<span style=\"color: #555555;\">::<\/span>sentinel_for<span style=\"color: #555555;\">&lt;<\/span>I<span style=\"color: #555555;\">&gt;<\/span> S,\n         <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Comp<\/span> <span style=\"color: #555555;\">=<\/span> ranges<span style=\"color: #555555;\">::<\/span>less, <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Proj<\/span> <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>identity<span style=\"color: #555555;\">&gt;<\/span>\nrequires std<span style=\"color: #555555;\">::<\/span>sortable<span style=\"color: #555555;\">&lt;<\/span>I, Comp, Proj<span style=\"color: #555555;\">&gt;<\/span>\nconstexpr I sort(I first, S last, Comp comp <span style=\"color: #555555;\">=<\/span> {}, Proj proj <span style=\"color: #555555;\">=<\/span> {});\n\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span>ranges<span style=\"color: #555555;\">::<\/span>random_access_range R, <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Comp<\/span> <span style=\"color: #555555;\">=<\/span> ranges<span style=\"color: #555555;\">::<\/span>less, \n          <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Proj<\/span> <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>identity<span style=\"color: #555555;\">&gt;<\/span>\nrequires std<span style=\"color: #555555;\">::<\/span>sortable<span style=\"color: #555555;\">&lt;<\/span>ranges<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">iterator_t<\/span><span style=\"color: #555555;\">&lt;<\/span>R<span style=\"color: #555555;\">&gt;<\/span>, Comp, Proj<span style=\"color: #555555;\">&gt;<\/span>\nconstexpr ranges<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">borrowed_iterator_t<\/span><span style=\"color: #555555;\">&lt;<\/span>R<span style=\"color: #555555;\">&gt;<\/span> sort(R<span style=\"color: #555555;\">&amp;&amp;<\/span> r, Comp comp <span style=\"color: #555555;\">=<\/span> {}, Proj proj <span style=\"color: #555555;\">=<\/span> {});\n<\/pre>\n<\/div>\n<div>\n<div>When you study the first overload, you notice that it takes a sortable range<code> R<\/code>, a predicate <code>Comp<\/code>, and a projection <code>Proj<\/code>. The predicate <code>Comp<\/code> uses for default <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/functional\/ranges\/less\">ranges::less<\/a>, and the projection <code>Proj<\/code> the identity <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/functional\/identity\">std::identity<\/a> that does return its arguments unchanged. <code>std::identity<\/code> have been added with C++20, a function object defined in the header &lt;<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/header\/functional\">functional<\/a>&gt;.<\/div>\n<div><\/div>\n<div>In short, here are the components:<\/div>\n<div><\/div>\n<ul>\n<li>Comparators: <code>Comp <\/code>(binary functions that return a boolean)<code><br \/>\n<\/code><\/li>\n<li>Projections: <code>Proj <\/code>(mapping of a set into a subset)<code><br \/>\n<\/code><\/li>\n<li>Sentinel:<code> std::sentinel_for&lt;I&gt;<\/code> (a unique value that indicates\u00a0 the end of a sequence)<code><br \/>\n<\/code><\/li>\n<li>Concepts: <code>std::random_access_iterator, std::sortable&lt;I, Comp, Proj&gt;<\/code>, and <code>std::sentinel_for&lt;I&gt;<\/code><\/li>\n<\/ul>\n<p>In contrast, the second overload does not return an Iterator I, but a<code> ranges::borrowed_iterator_t<\/code>. Of course, this is also a concept and guarantees that the returned iterator is safe to use afterward. Consequentially, we call this iterator a safe iterator. I will write more about <code>std::ranges::borrowed_iterator_t<\/code> in an upcoming post.<\/p>\n<p>A projection is a mapping of a set into a subset. What does this mean?<\/p>\n<h2>Projection<\/h2>\n<div>The algorithms of the ranges library operate directly on the container. This is due to the fact, that the projection is by default\u00a0<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/functional\/identity\">std::identity<\/a>.<\/div>\n<div><\/div>\n<div>In the following example, I apply a projection to the data type <code>PhoneBookEntry<\/code>.<\/div>\n<div><\/div>\n<div><\/div>\n<\/div>\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;\">\/\/ rangeProjection.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;algorithm&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;functional&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\n \n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> PhoneBookEntry{                                                   <em><span style=\"color: #0099ff;\">\/\/ (1)<\/span><\/em>\n    std<span style=\"color: #555555;\">::<\/span>string name;\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> number;\n};\n\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">printPhoneBook<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>PhoneBookEntry<span style=\"color: #555555;\">&gt;&amp;<\/span> phoneBook) {\n    <span style=\"color: #006699; font-weight: bold;\">for<\/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> entry<span style=\"color: #555555;\">:<\/span> phoneBook) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"(\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> entry.name <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\", \"<\/span> \n                                                        <span style=\"color: #555555;\">&lt;&lt;<\/span> entry.number <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\")\"<\/span>;\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>;\n}\n \n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\n\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\n\n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>PhoneBookEntry<span style=\"color: #555555;\">&gt;<\/span> phoneBook{ {<span style=\"color: #cc3300;\">\"Brown\"<\/span>, <span style=\"color: #ff6600;\">111<\/span>}, {<span style=\"color: #cc3300;\">\"Smith\"<\/span>, <span style=\"color: #ff6600;\">444<\/span>}, \n    {<span style=\"color: #cc3300;\">\"Grimm\"<\/span>, <span style=\"color: #ff6600;\">666<\/span>}, {<span style=\"color: #cc3300;\">\"Butcher\"<\/span>, <span style=\"color: #ff6600;\">222<\/span>}, {<span style=\"color: #cc3300;\">\"Taylor\"<\/span>, <span style=\"color: #ff6600;\">555<\/span>}, {<span style=\"color: #cc3300;\">\"Wilson\"<\/span>, <span style=\"color: #ff6600;\">333<\/span>} };\n\n    std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>sort(phoneBook, {}, <span style=\"color: #555555;\">&amp;<\/span>PhoneBookEntry<span style=\"color: #555555;\">::<\/span>name);   <span style=\"color: #0099ff; font-style: italic;\">\/\/ ascending by name (2)<\/span>\n    printPhoneBook(phoneBook);\n\n    std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>sort(phoneBook, std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>greater() , \n                      <span style=\"color: #555555;\">&amp;<\/span>PhoneBookEntry<span style=\"color: #555555;\">::<\/span>name);                  <span style=\"color: #0099ff; font-style: italic;\">\/\/ descending by name (3)<\/span>\n    printPhoneBook(phoneBook);\n\n    std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>sort(phoneBook, {}, <span style=\"color: #555555;\">&amp;<\/span>PhoneBookEntry<span style=\"color: #555555;\">::<\/span>number); <span style=\"color: #0099ff; font-style: italic;\">\/\/ ascending by number (4)<\/span>\n    printPhoneBook(phoneBook);\n\n     std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>sort(phoneBook, std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>greater(), \n                       <span style=\"color: #555555;\">&amp;<\/span>PhoneBookEntry<span style=\"color: #555555;\">::<\/span>number);              <span style=\"color: #0099ff; font-style: italic;\">\/\/ descending by number (5)<\/span>\n    printPhoneBook(phoneBook);\n    \n}\n<\/pre>\n<\/div>\n<p><code>phoneBook<\/code> (line 1) has structs of type <code>PhoneBookEntry<\/code> (line 1). A <code>PhoneBookEntry<\/code> consists of a <code>name<\/code> and a\u00a0<code>number<\/code>. Thanks to projections, the <code>phoneBook<\/code> can be sorted in ascending order by <code>name<\/code> (line 2), descending order by <code>name<\/code> (line 3), ascending order by <code>number<\/code> (line 4), and descending order by <code>number<\/code> (line 5). The empty curly braces in the expression <code>std::ranges::sort(phoneBook, {}, &amp;PhoneBookEntry::name)<\/code> cause the default construction of the sorting criteria that is, in this case, <code>std::less<\/code>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6362\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/05\/rangeProjection.png\" alt=\"rangeProjection\" width=\"600\" height=\"260\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/05\/rangeProjection.png 781w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/05\/rangeProjection-300x130.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/05\/rangeProjection-768x333.png 768w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>You can use a callable such as a lambda expression when your projection is more demanding.<\/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;\">\/\/ rangeProjectionCallable.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;algorithm&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;functional&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\n \n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> PhoneBookEntry{ \n    std<span style=\"color: #555555;\">::<\/span>string name;\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> number;\n};\n\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">printPhoneBook<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>PhoneBookEntry<span style=\"color: #555555;\">&gt;&amp;<\/span> phoneBook) {\n    <span style=\"color: #006699; font-weight: bold;\">for<\/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> entry<span style=\"color: #555555;\">:<\/span> phoneBook) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"(\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> entry.name <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\", \"<\/span> \n                                                        <span style=\"color: #555555;\">&lt;&lt;<\/span> entry.number <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\")\"<\/span>;\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"<\/span><span style=\"color: #cc3300; font-weight: bold;\">\\n\\n<\/span><span style=\"color: #cc3300;\">\"<\/span>;\n}\n \n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\n\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\n\n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>PhoneBookEntry<span style=\"color: #555555;\">&gt;<\/span> phoneBook{ {<span style=\"color: #cc3300;\">\"Brown\"<\/span>, <span style=\"color: #ff6600;\">111<\/span>}, {<span style=\"color: #cc3300;\">\"Smith\"<\/span>, <span style=\"color: #ff6600;\">444<\/span>}, \n    {<span style=\"color: #cc3300;\">\"Grimm\"<\/span>, <span style=\"color: #ff6600;\">666<\/span>}, {<span style=\"color: #cc3300;\">\"Butcher\"<\/span>, <span style=\"color: #ff6600;\">222<\/span>}, {<span style=\"color: #cc3300;\">\"Taylor\"<\/span>, <span style=\"color: #ff6600;\">555<\/span>}, {<span style=\"color: #cc3300;\">\"Wilson\"<\/span>, <span style=\"color: #ff6600;\">333<\/span>} };\n\n    std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>sort(phoneBook, {}, <span style=\"color: #555555;\">&amp;<\/span>PhoneBookEntry<span style=\"color: #555555;\">::<\/span>name);                    <em> <span style=\"color: #0099ff;\">\/\/ (1)<\/span><\/em>\n    printPhoneBook(phoneBook);\n\n    std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>sort(phoneBook, {}, [](<span style=\"color: #006699; font-weight: bold;\">auto<\/span> p){ <span style=\"color: #006699; font-weight: bold;\">return<\/span> p.name; } );            <em><span style=\"color: #0099ff;\"> \/\/ (2)<\/span><\/em>\n    printPhoneBook(phoneBook);\n\n    std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>sort(phoneBook, {}, [](<span style=\"color: #006699; font-weight: bold;\">auto<\/span> p) {                               <em><span style=\"color: #0099ff;\"> \/\/ (3)<\/span><\/em>\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> std<span style=\"color: #555555;\">::<\/span>to_string(p.number) <span style=\"color: #555555;\">+<\/span> p.name; \n    });\n    printPhoneBook(phoneBook);\n\n    std<span style=\"color: #555555;\">::<\/span>ranges<span style=\"color: #555555;\">::<\/span>sort(phoneBook, [](<span style=\"color: #006699; font-weight: bold;\">auto<\/span> p, <span style=\"color: #006699; font-weight: bold;\">auto<\/span> p2) {                          <em><span style=\"color: #0099ff;\"> \/\/ (4)<\/span><\/em>\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> std<span style=\"color: #555555;\">::<\/span>to_string(p.number) <span style=\"color: #555555;\">+<\/span> p.name <span style=\"color: #555555;\">&lt;<\/span> \n               std<span style=\"color: #555555;\">::<\/span>to_string(p2.number) <span style=\"color: #555555;\">+<\/span> p2.name; \n    });\n    printPhoneBook(phoneBook);\n    \n}\n<\/pre>\n<\/div>\n<div>\n<div><code>std::ranges::sort<\/code> in line (1) uses the attribute <code>PhoneBookEntry::name<\/code> as a projection. Line (2) shows the equivalent lambda expression<code> [](auto p){ return p.name; }<\/code> as projection. The projection in line (3) is more demanding. It uses the stringified number concatenated with the<code> p.name.<\/code> Of course, you can use the concatenated stringified number and the name directly as sorting criteria. In this case, the algorithm call in line (3) is easier to read than in line (4). I want to emphasize this. Line (3) uses a projection as a sorting criterion, but line (4) is parametrized<code> std::ranges::sort<\/code> with a binary predicate given by the lambda expression.<\/div>\n<div><\/div>\n<div><\/div>\n<div><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6363\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/05\/rangeProjectionCallableNew.png\" alt=\"rangeProjectionCallable\" width=\"600\" height=\"246\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/05\/rangeProjectionCallableNew.png 781w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/05\/rangeProjectionCallableNew-300x123.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/05\/rangeProjectionCallableNew-768x315.png 768w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/div>\n<div><\/div>\n<div>Most ranges algorithms support projections.<\/div>\n<h2>What&#8217;s next?<\/h2>\n<p>In my next post, I will write about sentinels. They specify the end of a range and can be regarded as generalized end iterators.<\/p>\n<div><\/div>\n<div><\/div>\n<div><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>The algorithms of the ranges library are lazy, can work directly on the container, and can easily be composed. But they have more to offer: projections. A projection is a mapping of a set into a subset. Let me show you in this post what that means:<\/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":[413],"class_list":["post-6364","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-ranges"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6364","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=6364"}],"version-history":[{"count":2,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6364\/revisions"}],"predecessor-version":[{"id":8395,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6364\/revisions\/8395"}],"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=6364"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=6364"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=6364"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}