{"id":5799,"date":"2019-10-23T20:29:52","date_gmt":"2019-10-23T20:29:52","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/thebigfour\/"},"modified":"2023-07-29T18:29:33","modified_gmt":"2023-07-29T18:29:33","slug":"thebigfour","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/thebigfour\/","title":{"rendered":"C++20: The Big Four"},"content":{"rendered":"<p>This post presents you the big four: concepts, ranges, coroutines, and modules.<\/p>\n<p><!--more--><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5795\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/TimelineCpp20BigFourUpdate.png\" alt=\"TimelineCpp20BigFourUpdate\" width=\"650\" height=\"224\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/TimelineCpp20BigFourUpdate.png 1113w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/TimelineCpp20BigFourUpdate-300x104.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/TimelineCpp20BigFourUpdate-1024x353.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/TimelineCpp20BigFourUpdate-768x265.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p>C++20 has a lot to offer. Before I give you a first impression of the big four, here is an overview of C++20. Besides the big four, many features affect the core language, the library, and the concurrency capabilities of C++20.<\/p>\n<h2>Compiler Support for C++20<\/h2>\n<p>Playing with the new features is the easiest way to get used to them. Okay. This approach arises immediately the question: Which C++20 features are supported by which compiler? As so often, <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/compiler_support\">cppreference.com\/compiler_support<\/a> gives you the answer to the core language and the library.<\/p>\n<p>To make it simple, the brand-new GCC, Clang, and EDG compilers give the best support to the core language. Additionally, the MSVC and Apple Clang compiler support also many C++20 features.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5796\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Core.PNG\" alt=\"Core\" width=\"600\" height=\"432\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Core.PNG 2362w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Core-300x216.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Core-1024x737.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Core-768x553.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Core-1536x1106.png 1536w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Core-2048x1474.png 2048w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>The story is similar to the library. GCC has the best support for the library, followed by Clang and the MSVC compiler.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5797\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Library.PNG\" alt=\"Library\" width=\"600\" height=\"448\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Library.PNG 2330w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Library-300x224.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Library-1024x764.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Library-768x573.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Library-1536x1146.png 1536w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/Library-2048x1529.png 2048w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>The screenshots show only the beginning of the tables, but they also give you an answer which is not so satisfying. Even if you use all brand-new compilers, many features are not supported by any compiler.<\/p>\n<p>Often, you find workarounds to play with the new features. Here are two examples:<\/p>\n<ul>\n<li>Concepts: GCC supports a previous version of concepts.<\/li>\n<li><span style=\"font-family: courier new, courier;\">std::jthread<\/span>: Nicolai Josuttis maintain a draft implementation on <a href=\"https:\/\/github.com\/josuttis\/jthread\">GitHub<\/a>.<\/li>\n<\/ul>\n<p>To make my story short. The situation is not so bad. <span class=\"tlid-translation translation\" lang=\"en\"><span class=\"\" title=\"\">With a bit of tinkering, many new features can be tried out. I will mention this little tinkering if necessary.<br \/>\n<\/span><\/span><\/p>\n<p>But now, let me give you a bird-eyes view of the new features. Of course, we should start with the big four.<\/p>\n<h2>The Big Four<\/h2>\n<h3>Concepts<\/h3>\n<p>The key idea of generic programming with templates is to define functions and classes which can be used with various types. Often it happens that you instantiate a template with the wrong type. The result is typically a few pages of cryptic error messages. This sad story ends with concepts. Concepts empower you to write requirements for your templates which the compiler can check. Concepts revolutionize the way we think about and write generic code. Here is why:<\/p>\n<ul>\n<li>Requirements for templates are part of the interface.<\/li>\n<li>The overloading of functions or specialization of class templates can be based on concepts.<\/li>\n<li>We get an improved error message because the compiler compares the requirements of the template parameter with the actual template arguments.<\/li>\n<\/ul>\n<p>However, this is not the end of the story.<\/p>\n<ul>\n<li>You can use predefined concepts or define your own.<\/li>\n<li>The usage of auto and concepts is unified. Instead of auto, you can use a concept.<\/li>\n<li>If a function declaration uses a concept, it automatically becomes a function template. Writing function templates is, therefore, as easy as writing a function.<\/li>\n<\/ul>\n<p>The following code snippet shows you the definition and the usage of the straightforward concept <span style=\"font-family: courier new, courier;\">Integral<\/span>:<\/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: #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>\nconcept Integral = std<span style=\"color: #555555;\">::<\/span>is_integral<span style=\"color: #555555;\">&lt;<\/span>T<span style=\"color: #555555;\">&gt;::<\/span>value;\n\nIntegral <span style=\"color: #006699; font-weight: bold;\">auto<\/span> gcd(Integral <span style=\"color: #006699; font-weight: bold;\">auto<\/span> a,     \n                  Integral <span style=\"color: #006699; font-weight: bold;\">auto<\/span> b){\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span>( b <span style=\"color: #555555;\">==<\/span> <span style=\"color: #ff6600;\">0<\/span> ) <span style=\"color: #006699; font-weight: bold;\">return<\/span> a; \n    <span style=\"color: #006699; font-weight: bold;\">else<\/span> <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #cc00ff;\">gcd<\/span>(b, a <span style=\"color: #555555;\">%<\/span> b);\n}\n<\/pre>\n<\/div>\n<p>Integral is the concept that requires from it type-parameter <span style=\"font-family: courier new, courier;\">T<\/span> that <span style=\"font-family: courier new, courier;\">std::is_integral&lt;T&gt;::value <\/span>holds. <span style=\"font-family: courier new, courier;\">std::is_integral&lt;T&gt;::value<\/span> is a function from the type-traits library which checks at compile-time if <span style=\"font-family: courier new, courier;\">T<\/span> is integral. If <span style=\"font-family: courier new, courier;\">std::is_integral&lt;T&gt;::value<\/span> evaluates to <span style=\"font-family: courier new, courier;\">true,<\/span> all is fine. If not, you get a compile-time error. Here are my posts to the type-traits library for the curious ones &#8211; and you should be curious.<\/p>\n<p>The gcd algorithm determines the greatest common divisor based on the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Euclidean_algorithm\">Euclidean algorithm<\/a>.\u00a0 I used the so-called abbreviated function template syntax to define <span style=\"font-family: courier new, courier;\">gcd.<\/span> <span style=\"font-family: courier new, courier;\">gcd<\/span> requires, from its arguments and return type, that they support the concept <span style=\"font-family: courier new, courier;\">Integral<\/span>.\u00a0 <span style=\"font-family: courier new, courier;\">gcd<\/span> is a function template that puts requirements on its arguments and return value. When I remove the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Syntactic_sugar\">syntactic sugar<\/a>, maybe you can see the fundamental nature of <span style=\"font-family: courier new, courier;\">gcd<\/span>.<\/p>\n<p>Here is the semantically equivalent <span style=\"font-family: courier new, courier;\">gcd<\/span> algorithm.<\/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: #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>\nrequires Integral<span style=\"color: #555555;\">&lt;<\/span>T<span style=\"color: #555555;\">&gt;<\/span>()\nT gcd(T a, T b){\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span>( b <span style=\"color: #555555;\">==<\/span> <span style=\"color: #ff6600;\">0<\/span> ) <span style=\"color: #006699; font-weight: bold;\">return<\/span> a; \n    <span style=\"color: #006699; font-weight: bold;\">else<\/span> <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #cc00ff;\">gcd<\/span>(b, a <span style=\"color: #555555;\">%<\/span> b);\n}\n<\/pre>\n<\/div>\n<p>If you don&#8217;t see the fundamental nature of <span style=\"font-family: courier new, courier;\">gcd<\/span>, you have to wait for my posts to concepts in a few weeks.<\/p>\n<h3>Ranges Library<\/h3>\n<p>The ranges library is the first customer of concepts. It supports algorithms that<\/p>\n<ul>\n<li>can operate directly on the container; you don&#8217;t need iterators to specify a range<\/li>\n<li>can be evaluated lazily<\/li>\n<li>can be composed<\/li>\n<\/ul>\n<p>To make it short: The ranges library supports functional patterns.<\/p>\n<p>Okay, code may help more than words. The following functions show function composition with the pipe symbol.<\/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: #009999;\">#include &lt;vector&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;ranges&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n \n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\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> ints{<span style=\"color: #ff6600;\">0<\/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  <span style=\"color: #006699; font-weight: bold;\">auto<\/span> even <span style=\"color: #555555;\">=<\/span> [](<span style=\"color: #007788; font-weight: bold;\">int<\/span> i){ <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #ff6600;\">0<\/span> <span style=\"color: #555555;\">==<\/span> i <span style=\"color: #555555;\">%<\/span> <span style=\"color: #ff6600;\">2<\/span>; };\n  <span style=\"color: #006699; font-weight: bold;\">auto<\/span> square <span style=\"color: #555555;\">=<\/span> [](<span style=\"color: #007788; font-weight: bold;\">int<\/span> i) { <span style=\"color: #006699; font-weight: bold;\">return<\/span> i <span style=\"color: #555555;\">*<\/span> i; };\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> ints <span style=\"color: #555555;\">|<\/span> std<span style=\"color: #555555;\">::<\/span>view<span style=\"color: #555555;\">::<\/span>filter(even) <span style=\"color: #555555;\">|<\/span> \n                      std<span style=\"color: #555555;\">::<\/span>view<span style=\"color: #555555;\">::<\/span>transform(square)) {\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> i <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">' '<\/span>;             <span style=\"color: #0099ff; font-style: italic;\">\/\/ 0 4 16<\/span>\n  }\n}\n<\/pre>\n<\/div>\n<p><span style=\"font-family: courier new, courier;\">even<\/span> is a lambda function that returns if a i is even, and the lambda function <span style=\"font-family: courier new, courier;\">square<\/span> maps i to its square. The rest ist function composition, which you have to read from left to right: <span style=\"font-family: courier new, courier; color: #000000;\">for (int i : ints | std::view::filter(even) | std::view::transform(square)). <\/span><span style=\"color: #000000;\">Apply the filter even on each element of ints and map each remaining element to its <span style=\"font-family: courier new, courier;\">square<\/span>. If you are familiar with functional programming, this reads like prose. <\/span><\/p>\n<h3>Coroutines<\/h3>\n<p>Coroutines are generalized functions that can be suspended and resumed while keeping their state. Coroutines are the usual way to write event-driven applications. An event-driven application can be simulations, games, servers, user interfaces, or even algorithms. Coroutines are also typically used for <a href=\"https:\/\/en.wikipedia.org\/wiki\/Cooperative_multitasking\">cooperative multitasking<\/a>.<\/p>\n<p>We don&#8217;t get with C++20 concrete coroutines; we will get a framework for writing our coroutines. The framework for writing coroutines consists of more than 20 functions that you partially have to implement and partially could overwrite. Therefore, you can tailor the coroutine to your needs.<\/p>\n<p>Let me show you the usage of a special coroutine. The following program uses a generator for an infinite data stream.<\/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%;\">Generator<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> getNext(<span style=\"color: #007788; font-weight: bold;\">int<\/span> start <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #007788; font-weight: bold;\">int<\/span> step <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">1<\/span>){\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> value <span style=\"color: #555555;\">=<\/span> start;\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;\">0<\/span>;; <span style=\"color: #555555;\">++<\/span>i){\n        co_yield value;            <span style=\"color: #0099ff; font-style: italic;\">\/\/ 1<\/span>\n        value <span style=\"color: #555555;\">+=<\/span> step;\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    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"getNext():\"<\/span>;\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> gen <span style=\"color: #555555;\">=<\/span> getNext();\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;\">0<\/span>; i <span style=\"color: #555555;\">&lt;=<\/span> <span style=\"color: #ff6600;\">10<\/span>; <span style=\"color: #555555;\">++<\/span>i) {\n        gen.next();               <span style=\"color: #0099ff; font-style: italic;\">\/\/ 2<\/span>\n        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> gen.getValue();                  \n    }\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    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"getNext(100, -10):\"<\/span>;\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> gen2 <span style=\"color: #555555;\">=<\/span> getNext(<span style=\"color: #ff6600;\">100<\/span>, <span style=\"color: #555555;\">-<\/span><span style=\"color: #ff6600;\">10<\/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> <span style=\"color: #ff6600;\">0<\/span>; i <span style=\"color: #555555;\">&lt;=<\/span> <span style=\"color: #ff6600;\">20<\/span>; <span style=\"color: #555555;\">++<\/span>i) {\n        gen2.next();             <span style=\"color: #0099ff; font-style: italic;\">\/\/ 3<\/span>\n        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> gen2.getValue();\n    }\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}\n<\/pre>\n<\/div>\n<p>Okay, I have to add a few words. This piece is only a code snippet. The function <span style=\"font-family: courier new, courier;\">getNext<\/span> is a coroutine because it uses the keyword<span style=\"font-family: courier new, courier;\"> co_yield. getNext<\/span> has an infinite loop that returns the <span style=\"font-family: courier new, courier;\">value<\/span> after <span style=\"font-family: courier new, courier;\">co_yield<\/span>. A call to <span style=\"font-family: courier new, courier;\">next()<\/span> (lines 2 and 3) resumes the coroutine, and the following <span style=\"font-family: courier new, courier;\">getValue<\/span> call gets the value. After the <span style=\"font-family: 'courier new', courier;\">getNext<\/span> call, the coroutine pauses once more. It pauses until the following <span style=\"font-family: courier new, courier;\">next()<\/span> call. There is one big unknown in my example. This unknown is the return value <span style=\"font-family: courier new, courier;\">Generator&lt;int&gt;<\/span> of the <span style=\"font-family: courier new, courier;\">getNext<\/span> function. Here the complicated stuff starts, which will be part of detailed posts to coroutines.<\/p>\n<p>Thanks to the Wandbox online compiler, I can show you the program&#8217;s output.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5798\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/infiniteDataStream.PNG\" alt=\"infiniteDataStream\" width=\"500\" height=\"124\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/infiniteDataStream.PNG 2037w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/infiniteDataStream-300x74.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/infiniteDataStream-1024x253.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/infiniteDataStream-768x190.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/10\/infiniteDataStream-1536x380.png 1536w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<h3>Modules<\/h3>\n<p>I make modules relatively short because the post is already too long.<\/p>\n<p>Modules promise:<\/p>\n<ul>\n<li>Faster compile times<\/li>\n<li>Isolation of macros<\/li>\n<li>Express the logical structure of the code<\/li>\n<li>Make header files superfluous<\/li>\n<li>Get rid of ugly macro workarounds<\/li>\n<\/ul>\n<h2>What&#8217;s next?<\/h2>\n<p>After the high-level overview of the big four, I will continue in my <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-20-the-core-language\">next post <\/a>with the core language features, as shown in my image.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post presents you the big four: concepts, ranges, coroutines, and modules.<\/p>\n","protected":false},"author":21,"featured_media":5795,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[415,445,443,413],"class_list":["post-5799","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-concepts","tag-coroutines","tag-modules","tag-ranges"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5799","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=5799"}],"version-history":[{"count":2,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5799\/revisions"}],"predecessor-version":[{"id":7934,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5799\/revisions\/7934"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5795"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5799"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5799"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5799"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}