{"id":5493,"date":"2018-08-22T19:24:40","date_gmt":"2018-08-22T19:24:40","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-rules-for-constants-and-immutability\/"},"modified":"2018-08-22T19:24:40","modified_gmt":"2018-08-22T19:24:40","slug":"c-core-guidelines-rules-for-constants-and-immutability","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-rules-for-constants-and-immutability\/","title":{"rendered":"C++ Core Guidelines: Rules for Constants and Immutability"},"content":{"rendered":"<p>Making objects or methods <code>const<\/code> has two benefits. First, the compiler will complain when you break the contract. Second, you tell the user of the interface that the function will not modify the arguments.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5489\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/precious-1199183_1920.jpg\" alt=\"precious 1199183 1920\" width=\"500\" height=\"281\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/precious-1199183_1920.jpg 1920w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/precious-1199183_1920-300x169.jpg 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/precious-1199183_1920-1024x576.jpg 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/precious-1199183_1920-768x432.jpg 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/precious-1199183_1920-1536x864.jpg 1536w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>The C++ Core Guidelines have five rules to <code>const<\/code>, immutability, and <code>constexpr<\/code>. Here are they:<\/p>\n<ul>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconst-immutable\">Con.1: By default, make objects immutable<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconst-fct\">Con.2: By default, make member functions <code class=\"highlighter-rouge no-highlight\">const<\/code><\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconst-ref\">Con.3: By default, pass pointers and references to <code class=\"highlighter-rouge no-highlight\">const<\/code>s<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconst-const\">Con.4: Use <code class=\"highlighter-rouge no-highlight\">const<\/code> to define objects with values that do not change after construction<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconst-constexpr\">Con.5: Use <code class=\"highlighter-rouge no-highlight\">constexpr<\/code> for values that can be computed at compile time<\/a><\/li>\n<\/ul>\n<p>Before I dive into the rules, I have to mention one expression. When someone writes about const and immutability, you often hear the term const correctness. According to the<a href=\"https:\/\/isocpp.org\/wiki\/faq\/const-correctness\"> C++ FAQ<\/a>, it means:<\/p>\n<ul>\n<li><strong>What is const correctness?<\/strong>&nbsp; It means using the keyword&nbsp;const&nbsp;to prevent&nbsp;const&nbsp;objects from getting mutated.<\/li>\n<\/ul>\n<p>Now, we know it. This post is about const correctness.<\/p>\n<h2><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconst-immutable\">Con.1: By default, make objects immutable<\/a><\/h2>\n<p>Okay, this rule is relatively easy. You can make a value of a built-in data type or an instance of a user-defined data type <code>const<\/code>. The effect is the same. If you want to change it, you will get what you deserve: a compiler error.<\/p>\n<p>&nbsp;<\/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;\">struct<\/span> Immutable{\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> val{<span style=\"color: #ff6600;\">12<\/span>};\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\r\n    <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">int<\/span> val{<span style=\"color: #ff6600;\">12<\/span>};\r\n    val <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">13<\/span>;      <span style=\"color: #0099ff; font-style: italic;\">\/\/ assignment of read-only variable 'val'<\/span>\r\n    \r\n    <span style=\"color: #006699; font-weight: bold;\">const<\/span> Immutable immu;\r\n    immu.val <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">13<\/span>; <span style=\"color: #0099ff; font-style: italic;\">\/\/ assignment of member 'Immutable::val' in read-only object<\/span>\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>&nbsp;The error messages from the GCC are compelling.<\/p>\n<\/p>\n<h2><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconst-fct\">Con.2: By default, make member functions <code class=\"highlighter-rouge no-highlight\">const<\/code><\/a><\/h2>\n<p>Declaring member functions as const has two benefits. An immutable object can only invoke const methods, and const methods cannot modify the underlying object. Once more. Here is a short example that includes the error messages from GCC:<\/p>\n<p>&nbsp;<\/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;\">struct<\/span> Immutable{\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> val{<span style=\"color: #ff6600;\">12<\/span>};\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> canNotModify() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        val <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">13<\/span>;  <span style=\"color: #0099ff; font-style: italic;\">\/\/ assignment of member 'Immutable::val' in read-only object<\/span>\r\n    }\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> modifyVal() {\r\n        val <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">13<\/span>;\r\n    }\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\r\n    <span style=\"color: #006699; font-weight: bold;\">const<\/span> Immutable immu;\r\n    immu.modifyVal();  <span style=\"color: #0099ff; font-style: italic;\">\/\/ passing 'const Immutable' as 'this' argument discards qualifiers <\/span>\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>This was not the whole truth. Sometimes, you distinguish between the logical and the physical constness of an object. Sounds strange. Right?<\/p>\n<ul>\n<li><strong>Physical constness<\/strong>: Your object is declared <code>const<\/code> and can, therefore, not be changed.<\/li>\n<li><strong>Logical constness<\/strong>: Your object is declared <code>const<\/code> but could be changed.<\/li>\n<\/ul>\n<p>Physical constness is relatively easy to get, but logical constness is. Let me modify the previous example a bit. Assume I want to change the attribute val in a <code>const<\/code> method.<\/p>\n<p>&nbsp;<\/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;\">\/\/ mutable.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Immutable{\r\n    <span style=\"color: #006699; font-weight: bold;\">mutable<\/span> <span style=\"color: #007788; font-weight: bold;\">int<\/span> val{<span style=\"color: #ff6600;\">12<\/span>};            <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> canNotModify() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        val <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">13<\/span>;\r\n    }\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    <span style=\"color: #006699; font-weight: bold;\">const<\/span> Immutable immu;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"val: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> immu.val <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    immu.canNotModify();            <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"val: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> immu.val <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The specifier <code>mutable<\/code> (1) made the magic possible. The <code>const<\/code> object can, therefore, invoke&nbsp; <code>const<\/code> method (2), which modifies <code>val<\/code>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5490\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/mutable.PNG\" alt=\"mutable\" width=\"250\" height=\"138\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/mutable.PNG 580w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/mutable-300x166.png 300w\" sizes=\"auto, (max-width: 250px) 100vw, 250px\" \/><\/p>\n<p>Here is an excellent use-case for <code>mutable<\/code>. Imagine your class has a read operation which should be <code>const<\/code>. Because you use the objects of the class concurrently, you have to protect the read method with a mutex. So the class gets a mutex, and you lock the mutex in the read operation. Now, you have a problem. Your read method cannot be <code>const<\/code> because of the locking of the mutex. The solution is to declare the mutex as <code>mutable<\/code>.<\/p>\n<p>Here is a sketch of the use case. Without mutable, this code would not work<\/p>\n<p>&nbsp;<\/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;\">struct<\/span> Immutable{\r\n    <span style=\"color: #006699; font-weight: bold;\">mutable<\/span> std<span style=\"color: #555555;\">::<\/span>mutex m;\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">read<\/span>() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {\r\n        std<span style=\"color: #555555;\">::<\/span>lock_guard<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>mutex<span style=\"color: #555555;\">&gt;<\/span> lck(m);\r\n        <span style=\"color: #0099ff; font-style: italic;\">\/\/ critical section<\/span>\r\n        ...\r\n    }\r\n};\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<h2><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconst-ref\">Con.3: By default, pass pointers and references to <code class=\"highlighter-rouge no-highlight\">const<\/code>s<\/a><\/h2>\n<p>Okay, this rule is quite apparent. If you pass pointers or references to consts to a function, the intention of the function is obvious. The pointed or referenced object would not be modified.<\/p>\n<p>&nbsp;<\/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: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">getCString<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">char<\/span><span style=\"color: #555555;\">*<\/span> cStr);\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">getCppString<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> std<span style=\"color: #555555;\">::<\/span>string<span style=\"color: #555555;\">&amp;<\/span> cppStr);\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Are both declarations equivalent? Not one hundred per cent. In the case of the function, the pointer could be null pointer. This means you have to check in the function vai<code> if (cStr) .... <\/code><\/p>\n<p>But there is more. The pointer and the pointee could be <code>const<\/code>.<\/p>\n<p>Here are the variations:<\/p>\n<ul>\n<li><code><strong>const char* cStr<\/strong><\/code>: <code>cStr<\/code> points to a <code>char<\/code> that is <code>const;<\/code> the pointee cannot be modified<\/li>\n<li><strong><code>char* const cStr<\/code><\/strong>:&nbsp; <code>cStr<\/code> is a <code>const<\/code> pointer; the pointer cannot be modified<\/li>\n<li><strong><code>const char* const cStr<\/code><\/strong>: <code>cStr<\/code> is a const pointer to a <code>char<\/code> that is <code>const<\/code>; neither the pointer nor the pointee could be modified<\/li>\n<\/ul>\n<p>Too complicated? Read the expressions from right to left. Still too complicated? Use a reference to const.<\/p>\n<p>I want to present the next two rules from the concurrency perspective. Let me do it together.<\/p>\n<h2><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconst-const\">Con.4: Use <code class=\"highlighter-rouge no-highlight\">const<\/code> to define objects with values that do not change after construction<\/a> and<a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconst-constexpr\"> Con.5: Use <code class=\"highlighter-rouge no-highlight\">constexpr<\/code> for values that can be computed at compile time<\/a><\/h2>\n<p>If you want to share a variable <code>immutable<\/code> between threads and this variable is declared as <code>const<\/code>, you are done. You can use <code>immutable<\/code> without synchronization, and you get the most performance out of your machine. The reason is quite simple. You should have a mutable, shared state to get a data race.<\/p>\n<ul>\n<li><code><strong>Data Race<\/strong><\/code>: At least two threads access a shared variable at the same time. At least one thread tries to modify it.<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5491\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/DataRace.PNG\" alt=\"DataRace\" width=\"300\" height=\"221\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/DataRace.PNG 376w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/DataRace-300x221.png 300w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>There is only one problem to solve. You have to initialize the shared variable in a thread-safe way. I have at least four ideas in my mind.<\/p>\n<ol>\n<li>Initialize the shared variable before you start a thread.<\/li>\n<li>Use the function<code> std::call_once<\/code> in combination with the flag <code>std::once_flag<\/code>.<\/li>\n<li>Use a <code>static<\/code> variable with block scope.<\/li>\n<li>Use a <code>constexpr<\/code> variable.<\/li>\n<\/ol>\n<p>Many people oversee variant 1, which is relatively easy to do right. You can read more about the thread-safe initialization of a variable in my previous post:<a href=\"https:\/\/www.modernescpp.com\/index.php\/thread-safe-initialization-of-data\"> Thread-safe Initialization of Data<\/a>.<\/p>\n<p>Rule Con.5 is about variant 4. When you declare a variable as constexpr <code>constexpr double totallyConst = 5.5;<\/code>, <span style=\"font-family: courier new, courier;\">totallyConst<\/span> is initialized at compile-time and, therefore, thread-safe.<\/p>\n<p>That was not all about <code>constexpr<\/code>. The C++ core guidelines forgot to mention a critical aspect of <code>constexpr<\/code>&nbsp;concurrent environments. <span style=\"font-family: courier new, courier;\">constexpr<\/span> functions are pure. Let&#8217;s have a look at the <code>constexpr gcd<\/code> .<\/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%;\">constexpr <span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">gcd<\/span>(<span style=\"color: #007788; font-weight: bold;\">int<\/span> a, <span style=\"color: #007788; font-weight: bold;\">int<\/span> b){\r\n  <span style=\"color: #006699; font-weight: bold;\">while<\/span> (b <span style=\"color: #555555;\">!=<\/span> <span style=\"color: #ff6600;\">0<\/span>){\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> t<span style=\"color: #555555;\">=<\/span> b;\r\n    b<span style=\"color: #555555;\">=<\/span> a <span style=\"color: #555555;\">%<\/span> b;\r\n    a<span style=\"color: #555555;\">=<\/span> t;\r\n  }\r\n  <span style=\"color: #006699; font-weight: bold;\">return<\/span> a;\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>First, what does pure mean? And second, what does sort of pure mean?<\/p>\n<p>A <code>constexpr<\/code> function can be executed at compile time. There is no state at compile time. When you use this <span style=\"font-family: courier new, courier;\">constexpr<\/span> function at runtime, the function is not, per see, pure. Pure functions are functions that always return the same result when given the same arguments. Pure functions are like infinitely large tables from which you get your value. Referential transparency is the guarantee that an expression always returns the same result when given the same arguments.<\/p>\n<p>Pure functions have a lot of advantages:<\/p>\n<ol>\n<li>The result can replace the function call.<\/li>\n<li>The execution of pure functions can automatically be distributed to other threads.<\/li>\n<li>A function call can be reordered.<\/li>\n<li>They can easily be refactored or tested in isolation.<\/li>\n<\/ol>\n<p>In particular, point 2 makes pure functions so precious in concurrent environments. The table shows the critical points of pure functions.<\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5492\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/pure.png\" alt=\"pure\" width=\"400\" height=\"99\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/pure.png 1081w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/pure-300x74.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/pure-1024x254.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/08\/pure-768x190.png 768w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p>\n<p>I want to stress one point. constexpr functions are not per se pure. They are pure when executed at compile time.<\/p>\n<h2>What&#8217;s next<\/h2>\n<p>That was it. I&#8217;m done with constness and immutability in the C++ core guidelines. In the next post, I will start to write about the future of C++: templates and generic programming.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Making objects or methods const has two benefits. First, the compiler will complain when you break the contract. Second, you tell the user of the interface that the function will not modify the arguments.<\/p>\n","protected":false},"author":21,"featured_media":5489,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[372],"tags":[],"class_list":["post-5493","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-modern-c"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5493","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=5493"}],"version-history":[{"count":0,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5493\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5489"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5493"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5493"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5493"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}