{"id":5867,"date":"2020-03-20T09:48:29","date_gmt":"2020-03-20T09:48:29","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-20-coroutines-the-first-overview\/"},"modified":"2023-09-28T07:46:05","modified_gmt":"2023-09-28T07:46:05","slug":"c-20-coroutines-the-first-overview","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-20-coroutines-the-first-overview\/","title":{"rendered":"C++20: Coroutines &#8211; A First Overview"},"content":{"rendered":"<p>C++20 provides four features that change how we think about and write modern C++: concepts, the ranges library, coroutines, and modules. I already wrote a few posts to <a href=\"https:\/\/www.modernescpp.com\/index.php\/tag\/concepts\">concepts<\/a> and the <a href=\"https:\/\/www.modernescpp.com\/index.php\/tag\/ranges-library\">ranges library<\/a>. Let&#8217;s have a closer look at coroutines.<\/p>\n<p><!--more--><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8406 size-full\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines.png\" alt=\"\" width=\"1068\" height=\"383\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines.png 1068w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines-300x108.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines-1030x369.png 1030w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines-768x275.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Coroutines-705x253.png 705w\" sizes=\"auto, (max-width: 1068px) 100vw, 1068px\" \/><\/p>\n<p>I want to use this post as a starting point to dive deeper into coroutines.<\/p>\n<p>Coroutines are functions that can suspend and resume their execution while keeping their state. The\u00a0evolution of functions goes in C++ one step further.\u00a0What I present as a new idea in C++20 is quite old. <a href=\"https:\/\/en.wikipedia.org\/wiki\/Melvin_Conway\">Melvin Conway<\/a> coined the term coroutine. He used it in his publication on compiler construction in 1963. <a href=\"https:\/\/en.wikipedia.org\/wiki\/Donald_Knuth\">Donald Knuth<\/a>\u00a0called procedures a particular case of coroutines.<\/p>\n<p>With the new keywords<span style=\"font-family: 'courier new', courier;\"> co_await<\/span> and <span style=\"font-family: 'courier new', courier;\">co_yield<\/span>, C++20 extends the execution of C++ functions with\u00a0two new concepts.<\/p>\n<ul>\n<li>Thanks to <strong><span style=\"font-family: 'courier new', courier;\">co_await expression<\/span><\/strong> expression, it is possible to suspend and resume the execution of the expression.\u00a0If you use <span style=\"font-family: 'courier new', courier;\">the co_await expression<\/span> in a function <span style=\"font-family: 'courier new', courier;\">func<\/span>, the call <span style=\"font-family: 'courier new', courier;\">auto getResult = func()<\/span> does not\u00a0block if the function result is unavailable. Instead of resource-consuming blocking, you have\u00a0resource-friendly waiting.<\/li>\n<li><span style=\"font-family: 'courier new', courier;\"><strong>co_yield expression<\/strong><\/span> expression allows it to write a generator function. The generator function returns a new\u00a0value each time. A generator function is a data stream from which you can pick values. The\u00a0data stream can be infinite. Consequentially, we are at the center of lazy evaluation.<\/li>\n<\/ul>\n<p>Before I present a generator function to show the difference between a function and coroutines, I want to say a few words about the evolution of functions.<\/p>\n<h2>Evolution of Functions<\/h2>\n<p>The following code example shows the various simplified steps in the evolution of functions.<\/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;\">\/\/ functionEvolution.cpp<\/span>\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">func1<\/span>() {\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #ff6600;\">1972<\/span>;\n}\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">func2<\/span>(<span style=\"color: #007788; font-weight: bold;\">int<\/span> arg) {\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> arg;\n}\n\n<span style=\"color: #007788; font-weight: bold;\">double<\/span> <span style=\"color: #cc00ff;\">func2<\/span>(<span style=\"color: #007788; font-weight: bold;\">double<\/span> arg) {\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> arg;\n}\n\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> T<span style=\"color: #555555;\">&gt;<\/span>\n<span style=\"color: #007788; font-weight: bold;\">T<\/span> func3(T arg) {\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> arg;\n}\n\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> FuncObject4 {\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span>()() { <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #ff6600;\">1998<\/span>;\n    }\n};\n\n<span style=\"color: #006699; font-weight: bold;\">auto<\/span> func5 <span style=\"color: #555555;\">=<\/span> [] {\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #ff6600;\">2011<\/span>;\n};\n\n<span style=\"color: #006699; font-weight: bold;\">auto<\/span> func6 <span style=\"color: #555555;\">=<\/span> [] (<span style=\"color: #006699; font-weight: bold;\">auto<\/span> arg){\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> arg;\n};\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\n\n    func1();        <span style=\"color: #0099ff; font-style: italic;\">\/\/ 1972<\/span>\n\n    func2(<span style=\"color: #ff6600;\">1998<\/span>);    <span style=\"color: #0099ff; font-style: italic;\">\/\/ 1998<\/span>\n    func2(<span style=\"color: #ff6600;\">1998.0<\/span>);  <span style=\"color: #0099ff; font-style: italic;\">\/\/ 1998.0<\/span>\n    func3(<span style=\"color: #ff6600;\">1998<\/span>);    <span style=\"color: #0099ff; font-style: italic;\">\/\/ 1998<\/span>\n    func3(<span style=\"color: #ff6600;\">1998.0<\/span>);  <span style=\"color: #0099ff; font-style: italic;\">\/\/ 1998.0<\/span>\n    FuncObject4 func4;\n    func4();        <span style=\"color: #0099ff; font-style: italic;\">\/\/ 1998<\/span>\n\n    func5();        <span style=\"color: #0099ff; font-style: italic;\">\/\/ 2011<\/span>\n\n    func6(<span style=\"color: #ff6600;\">2014<\/span>);    <span style=\"color: #0099ff; font-style: italic;\">\/\/ 2014<\/span>\n    func6(<span style=\"color: #ff6600;\">2014.0<\/span>);  <span style=\"color: #0099ff; font-style: italic;\">\/\/ 2014<\/span>\n\n}   \n<\/pre>\n<\/div>\n<ul>\n<li>Since the first C standard in 1972, we have functions: <span style=\"font-family: 'courier new', courier;\">func1<\/span>.<\/li>\n<li>With the first C++ standard in 1998, functions became way more powerful. We got\n<ul>\n<li>Function overloading:<span style=\"font-family: 'courier new', courier;\"> func2.<\/span><\/li>\n<li>Function templates:<span style=\"font-family: 'courier new', courier;\"> func3.<\/span><\/li>\n<li>Function objects: <span style=\"font-family: 'courier new', courier;\">func4<\/span>. Often, they are erroneous, and called functors. Function objects are due to the overload call operator (<span style=\"font-family: 'courier new', courier;\">operator ()<\/span>) objects, which can be invoked. The second pair of round braces in line (1) represents the function call parameters.<\/li>\n<\/ul>\n<\/li>\n<li>C++11 gave us lambda functions: <span style=\"font-family: 'courier new', courier;\">func5.<\/span><\/li>\n<li>With C++14, lambda functions can be generic: <span style=\"font-family: 'courier new', courier;\">func6.\u00a0<\/span><\/li>\n<\/ul>\n<p>Let&#8217;s go one step further. Generators are special coroutines.<\/p>\n<h2>Generators<\/h2>\n<p>In classical C++, I can implement a greedy generator.<\/p>\n<h3>A Greedy Generator<\/h3>\n<p>The following program is as straightforward as possible. The function <span style=\"font-family: 'courier new', courier;\">getNumbers<\/span> returns all integers from\u00a0<span style=\"font-family: 'courier new', courier;\">begin<\/span> to <span style=\"font-family: 'courier new', courier;\">end<\/span> incremented by inc. <span style=\"font-family: 'courier new', courier;\">begin<\/span> has to be smaller than <span style=\"font-family: 'courier new', courier;\">end<\/span>, and <span style=\"font-family: 'courier new', courier;\">inc<\/span> has to be positive.<\/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;\">\/\/ greedyGenerator.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\n\nstd<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> getNumbers(<span style=\"color: #007788; font-weight: bold;\">int<\/span> begin, <span style=\"color: #007788; font-weight: bold;\">int<\/span> end, <span style=\"color: #007788; font-weight: bold;\">int<\/span> inc <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">1<\/span>) {\n  \n    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> numbers;                      <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #007788; font-weight: bold;\">int<\/span> i <span style=\"color: #555555;\">=<\/span> begin; i <span style=\"color: #555555;\">&lt;<\/span> end; i <span style=\"color: #555555;\">+=<\/span> inc) {\n        numbers.push_back(i);\n    }\n  \n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> numbers;\n  \n}\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> main() {\n\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\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> getNumbers(<span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">10<\/span>, <span style=\"color: #ff6600;\">11<\/span>);\n  \n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #006699; font-weight: bold;\">auto<\/span> n<span style=\"color: #555555;\">:<\/span> numbers) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> n <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" \"<\/span>;\n  \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    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #006699; font-weight: bold;\">auto<\/span> n<span style=\"color: #555555;\">:<\/span> getNumbers(<span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #ff6600;\">101<\/span>, <span style=\"color: #ff6600;\">5<\/span>)) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> n <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" \"<\/span>;\n\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<\/pre>\n<\/div>\n<p>Of course, I am reinventing the wheel with <span style=\"font-family: 'courier new', courier;\">getNumbers<\/span> because that job could be done quite well with the algorithm<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/algorithm\/iota\">\u00a0std::iota<\/a>. The output of the program is as expected.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5201\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/02\/greedyGenerator.png\" alt=\"greedyGenerator\" width=\"500\" height=\"129\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/02\/greedyGenerator.png 674w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/02\/greedyGenerator-300x77.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>Two observations of the program are essential. On the one hand, the vector <span style=\"font-family: 'courier new', courier;\">numbers<\/span> in line (1) always get all values. This holds even if I\u2019m only interested in the first five elements of a vector with\u00a01000 elements. On the other hand, it\u2019s quite easy to transform the function <span style=\"font-family: 'courier new', courier;\">getNumbers<\/span> into a lazy\u00a0generator.<\/p>\n<h3>A Lazy Generator<\/h3>\n<p>That&#8217;s all.<\/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;\">\/\/ lazyGenerator.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\n\ngenerator<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> generatorForNumbers(<span style=\"color: #007788; font-weight: bold;\">int<\/span> begin, <span style=\"color: #007788; font-weight: bold;\">int<\/span> inc <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">1<\/span>) {\n  \n  <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #007788; font-weight: bold;\">int<\/span> i <span style=\"color: #555555;\">=<\/span> begin;; i <span style=\"color: #555555;\">+=<\/span> inc) {\n    co_yield i;\n  }\n  \n}\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> main() {\n\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\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> generatorForNumbers(<span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">10<\/span>);                   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\n  \n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #007788; font-weight: bold;\">int<\/span> i<span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">1<\/span>; i <span style=\"color: #555555;\">&lt;=<\/span> <span style=\"color: #ff6600;\">20<\/span>; <span style=\"color: #555555;\">++<\/span>i) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> numbers <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" \"<\/span>;       <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\n  \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    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #006699; font-weight: bold;\">auto<\/span> n<span style=\"color: #555555;\">:<\/span> generatorForNumbers(<span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #ff6600;\">5<\/span>)) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> n <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\" \"<\/span>;  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\n\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<\/pre>\n<\/div>\n<p>While the function <span style=\"font-family: 'courier new', courier;\">getNumbers<\/span> in the file <span style=\"font-family: 'courier new', courier;\">greedyGenerator.cpp<\/span> returns a std::vector, the\u00a0coroutine <span style=\"font-family: 'courier new', courier;\">generatorForNumbers<\/span> in <span style=\"font-family: 'courier new', courier;\">lazyGenerator.cpp<\/span> returns a generator. The generator <span style=\"font-family: 'courier new', courier;\">numbers<\/span>\u00a0in line (2) or<span style=\"font-family: 'courier new', courier;\"> generatorForNumbers(0, 5)<\/span> in line (3) return a new number on request. The range-based for-loop triggers the query. To be more precise, the query of the coroutine returns the value <span style=\"font-family: 'courier new', courier;\">i\u00a0via co_yield i<\/span> and immediately suspends its execution. If a new value is requested, the coroutine\u00a0resumes its execution exactly at that place.<\/p>\n<p><span style=\"color: #000000;\">The expression<span style=\"font-family: 'courier new', courier;\"> generatorForNumbers(0, 5)<\/span> in line (3) is a just-in-place usage of a generator.\u00a0I want to stress one point explicitly. The coroutine <span style=\"font-family: 'courier new', courier;\">generatorForNumbers<\/span> creates an infinite data\u00a0stream because the for-loop in line (3) has no end condition. This infinite data stream is fine if I only ask for a finite\u00a0number of values, such as in line (4). This does not hold for line (3) since there is no end condition. Consequentially, the expression runs forever.<\/span><\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>We don&#8217;t get C++20 concrete coroutines; we get a framework for writing our coroutines. You can assume that I have a lot to write about them.<\/p>\n<h2>First Virtual Meetup<\/h2>\n<p>I&#8217;m happy to give the first virtual talk for the C++ User Group in Munich. Here is the official invitation:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" alignleft size-full wp-image-5866\" style=\"margin: 20px; float: left;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/03\/MUC.png\" alt=\"MUC\" width=\"150\" height=\"150\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/03\/MUC.png 240w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/03\/MUC-150x150.png 150w\" sizes=\"auto, (max-width: 150px) 100vw, 150px\" \/><\/p>\n<div><\/div>\n<div><\/div>\n<div class=\"css-1dbjc4n r-xoduu5\"><span class=\"css-901oao css-16my406 r-1qd0xha r-ad9z0x r-bcqeeo r-qvutc0\">Help us fight social isolation and join us next Thursday for our first-ever virtual meetup! <a href=\"https:\/\/twitter.com\/rainer_grimm\">@rainer_grimm<\/a> will be talking about Concepts in C++20. March 26, 19:00 (CET).<\/span><\/div>\n<div class=\"css-1dbjc4n r-xoduu5\"><span class=\"css-901oao css-16my406 r-1qd0xha r-ad9z0x r-bcqeeo r-qvutc0\">Check out the full event description at\u00a0<a href=\"https:\/\/www.meetup.com\/de-DE\/MUCplusplus\/events\/269530229\/\">meetup.com\/MUCplusplus<\/a>. The stream is open for everyone; you don&#8217;t need to register on meetup for this one.<\/span><\/div>\n","protected":false},"excerpt":{"rendered":"<p>C++20 provides four features that change how we think about and write modern C++: concepts, the ranges library, coroutines, and modules. I already wrote a few posts to concepts and the ranges library. Let&#8217;s have a closer look at coroutines.<\/p>\n","protected":false},"author":21,"featured_media":8406,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[445],"class_list":["post-5867","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-coroutines"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5867","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=5867"}],"version-history":[{"count":2,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5867\/revisions"}],"predecessor-version":[{"id":8427,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5867\/revisions\/8427"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/8406"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5867"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5867"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5867"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}