{"id":5502,"date":"2018-09-06T19:47:42","date_gmt":"2018-09-06T19:47:42","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-type-erasure\/"},"modified":"2023-06-26T11:45:22","modified_gmt":"2023-06-26T11:45:22","slug":"c-core-guidelines-type-erasure","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-type-erasure\/","title":{"rendered":"C++ Core Guidelines: Type Erasure"},"content":{"rendered":"<p id=\"t5-combine-generic-and-oo-techniques-to-amplify-their-strengths-not-their-costs\">The rule &#8220;T.5: Combine generic and OO techniques to amplify their strengths, not their costs&#8221;&nbsp; of the core guidelines to generic programming uses type erasure as an example. Type erasure? Really! Of course, it takes me two posts to explain this advanced template technique.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5497\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/fear.png\" alt=\"fear\" width=\"500\" height=\"375\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/fear.png 640w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/fear-300x225.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>First of all: What does type erasure mean?<\/p>\n<ul>\n<li><strong>Type Erasure: <\/strong>Type Erasure enables using various concrete types through a single generic interface.<\/li>\n<\/ul>\n<p>Of course, you already often used type erasure in C++ or C. The C-ish type erasure is a void pointer; the C++-ish erasure is object orientation. Let&#8217;s start with a void pointer.<\/p>\n<h2>Void Pointer<\/h2>\n<p>Let&#8217;s have a closer look at the declaration of <code>std::qsort<\/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%;\"><span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">qsort<\/span>(<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #555555;\">*<\/span>ptr, std<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">size_t<\/span> count, std<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">size_t<\/span> size, cmp);\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>with:<\/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;\">int<\/span> <span style=\"color: #cc00ff;\">cmp<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #555555;\">*<\/span>a, <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #555555;\">*<\/span>b);\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The comparison function cmp<code><\/code> should return a<\/p>\n<ul>\n<li>negative integer: the&nbsp;first argument is less than the second<\/li>\n<li>zero: both arguments are equal<\/li>\n<li>positive integer: the&nbsp;first argument is greater than the second<\/li>\n<\/ul>\n<p>Thanks to the void pointer, <code>std::qsort<\/code> it is generally applicable but also quite error-prone.<\/p>\n<p>Maybe you want to sort a <code>std::vector&lt;int&gt;,<\/code> but you used a comparator for C-strings. The compiler can not catch this error because the type information was removed. You end with undefined behavior.<\/p>\n<p>In C++, we can do better:<\/p>\n<\/p>\n<h2>Object Orientation<\/h2>\n<p>Here is a simple example, which serves as a starting point for further variations.<\/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;\">\/\/ typeErasureOO.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> BaseClass{                                       <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n\t<span style=\"color: #006699; font-weight: bold;\">virtual<\/span> std<span style=\"color: #555555;\">::<\/span>string getName() <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">0<\/span>;\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Bar<span style=\"color: #555555;\">:<\/span> BaseClass{                                  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n\tstd<span style=\"color: #555555;\">::<\/span>string getName() <span style=\"color: #006699; font-weight: bold;\">const<\/span> override {\r\n\t    <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #cc3300;\">\"Bar\"<\/span>;\r\n\t}\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Foo<span style=\"color: #555555;\">:<\/span> BaseClass{                                  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n\tstd<span style=\"color: #555555;\">::<\/span>string getName() <span style=\"color: #006699; font-weight: bold;\">const<\/span> override{\r\n\t    <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #cc3300;\">\"Foo\"<\/span>;\r\n\t}\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">printName<\/span>(std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">const<\/span> BaseClass<span style=\"color: #555555;\">*&gt;<\/span> vec){      <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #006699; font-weight: bold;\">auto<\/span> v<span style=\"color: #555555;\">:<\/span> vec) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> v<span style=\"color: #555555;\">-&gt;<\/span>getName() <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\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\t\r\n\tstd<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n\t\r\n\tFoo foo;\r\n\tBar bar; \r\n\t\r\n\tstd<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">const<\/span> BaseClass<span style=\"color: #555555;\">*&gt;<\/span> vec{<span style=\"color: #555555;\">&amp;<\/span>foo, <span style=\"color: #555555;\">&amp;<\/span>bar};   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n\t\r\n\tprintName(vec);\r\n\t\r\n\tstd<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><code>std::vector&lt;const Base*&gt;<\/code> (1) has a pointer to a constant <code>BaseClasses<\/code>. <code>BaseClass<\/code> is abstract Base Class, which is used in (3). <code>Foo<\/code> and <code>Bar<\/code> (4) are the concrete classes.<\/p>\n<p>The output of the program is not so thrilling.<\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5498\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/typeErasureOO.png\" alt=\"typeErasureOO\" width=\"300\" height=\"178\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/typeErasureOO.png 612w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/typeErasureOO-300x178.png 300w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p id=\"firstHeading\" class=\"firstHeading\" lang=\"en\">To say it more formally. <code>Foo<\/code> and <code>Bar<\/code> implement the interface of the <code>BaseClass<\/code> and can, therefore, be used instead of <code>BaseClass.<\/code> This principle is called <a href=\"https:\/\/en.wikipedia.org\/wiki\/Liskov_substitution_principle\">Liskov substitution principle<\/a> and is type erasure in OO.<\/p>\n<p>In Object Orientated&nbsp; Programming, you implement an interface. In dynamically typed languages such as Python, you are not interested in interfaces; you are interested in behavior.<\/p>\n<h2>Templates<\/h2>\n<p>Let me make a short detour.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" alignleft size-full wp-image-5499\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/snake-312561_1280.png\" alt=\"snake 312561 1280\" width=\"300\" height=\"268\" style=\"margin: 20px; float: left;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/snake-312561_1280.png 1280w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/snake-312561_1280-300x268.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/snake-312561_1280-1024x915.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/snake-312561_1280-768x686.png 768w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>In Python, you care about behavior and not about formal interfaces. This idea is well-known as <a href=\"https:\/\/en.wikipedia.org\/wiki\/Duck_typing\">duck typing. <\/a>To make it short, the expression goes back to the poem from <a href=\"https:\/\/de.wikipedia.org\/wiki\/James_Whitcomb_Riley\">James <\/a><a href=\"https:\/\/de.wikipedia.org\/wiki\/James_Whitcomb_Riley\">Whitcomb<\/a><a href=\"https:\/\/de.wikipedia.org\/wiki\/James_Whitcomb_Riley\"> Rileys:<\/a> Here it is:<\/p>\n<p style=\"text-align: center;\">&nbsp;<\/p>\n<p style=\"text-align: center;\">\u201cWhen I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.\u201d<\/p>\n<p>What does that mean? Imagine a function <code>acceptOnlyDucks<\/code>&nbsp;that only accepts ducks as an argument. All derived types can invoke the function in statically typed languages such as C++. In Python, all types, which behave like <code>Duck<\/code>&#8216;s, can be used to invoke the function. To make it more concrete. If a bird behaves like&nbsp;&nbsp;<code>Duck<\/code> it is a <code>Duck<\/code>. Python often uses a proverb to describe this behavior quite well.<\/p>\n<p style=\"text-align: center;\">Don&#8217;t ask for permission; ask for forgiveness.<\/p>\n<p>In our Duck&#8217;s case, you invoke the function <code>acceptsOnlyDucks<\/code> with a bird and hope for the best. If something terrible happens, you catch the exception with an except clause. Often this strategy works very well and very fast in Python.<\/p>\n<p>Okay, this is the end of my detour. Maybe you wonder why I wrote about duck typing in this C++ post. The reason is quite straightforward. Thanks to templates, we have duck typing in C++. When you combine duck typing together with OO, it even becomes type-safe.<\/p>\n<p><code>std::function<\/code> as a polymorphic function wrapper is a nice example of type erasure in C++.<\/p>\n<h3>std::function<\/h3>\n<p><code>std::function<\/code> can accept everything which behaves like a function. To be more precise. This can be any callable such as a function, a function object, a function object created by <span style=\"font-family: courier new, courier;\">std::bind,<\/span> or just a lambda function.<\/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;\">\/\/ callable.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;cmath&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;functional&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;map&gt;<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">double<\/span> <span style=\"color: #cc00ff;\">add<\/span>(<span style=\"color: #007788; font-weight: bold;\">double<\/span> a, <span style=\"color: #007788; font-weight: bold;\">double<\/span> b){\r\n\t<span style=\"color: #006699; font-weight: bold;\">return<\/span> a <span style=\"color: #555555;\">+<\/span> b;\r\n}\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Sub{\r\n\t<span style=\"color: #007788; font-weight: bold;\">double<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span>()(<span style=\"color: #007788; font-weight: bold;\">double<\/span> a, <span style=\"color: #007788; font-weight: bold;\">double<\/span> b){\r\n\t\t<span style=\"color: #006699; font-weight: bold;\">return<\/span> a <span style=\"color: #555555;\">-<\/span> b;\r\n\t}\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">double<\/span> <span style=\"color: #cc00ff;\">multThree<\/span>(<span style=\"color: #007788; font-weight: bold;\">double<\/span> a, <span style=\"color: #007788; font-weight: bold;\">double<\/span> b, <span style=\"color: #007788; font-weight: bold;\">double<\/span> c){\r\n\t<span style=\"color: #006699; font-weight: bold;\">return<\/span> a <span style=\"color: #555555;\">*<\/span> b <span style=\"color: #555555;\">*<\/span> c;\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    <span style=\"color: #006699; font-weight: bold;\">using<\/span> <span style=\"color: #006699; font-weight: bold;\">namespace<\/span> std<span style=\"color: #555555;\">::<\/span>placeholders;\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    std<span style=\"color: #555555;\">::<\/span>map<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">char<\/span> , std<span style=\"color: #555555;\">::<\/span>function<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">double<\/span>(<span style=\"color: #007788; font-weight: bold;\">double<\/span>, <span style=\"color: #007788; font-weight: bold;\">double<\/span>)<span style=\"color: #555555;\">&gt;&gt;<\/span> dispTable{  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n        {<span style=\"color: #cc3300;\">'+'<\/span>, add },                                         <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n        {<span style=\"color: #cc3300;\">'-'<\/span>, Sub() },                                       <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n        {<span style=\"color: #cc3300;\">'*'<\/span>, std<span style=\"color: #555555;\">::<\/span>bind(multThree, <span style=\"color: #ff6600;\">1<\/span>, _1, _2) },             <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n        {<span style=\"color: #cc3300;\">'\/'<\/span>,[](<span style=\"color: #007788; font-weight: bold;\">double<\/span> a, <span style=\"color: #007788; font-weight: bold;\">double<\/span> b){ <span style=\"color: #006699; font-weight: bold;\">return<\/span> a <span style=\"color: #555555;\">\/<\/span> b; }}};      <span style=\"color: #0099ff; font-style: italic;\">\/\/ (5)<\/span>\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"3.5 + 4.5 = \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dispTable[<span style=\"color: #cc3300;\">'+'<\/span>](<span style=\"color: #ff6600;\">3.5<\/span>, <span style=\"color: #ff6600;\">4.5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"3.5 - 4.5 = \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dispTable[<span style=\"color: #cc3300;\">'-'<\/span>](<span style=\"color: #ff6600;\">3.5<\/span>, <span style=\"color: #ff6600;\">4.5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"3.5 * 4.5 = \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dispTable[<span style=\"color: #cc3300;\">'*'<\/span>](<span style=\"color: #ff6600;\">3.5<\/span>, <span style=\"color: #ff6600;\">4.5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"3.5 \/ 4.5 = \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dispTable[<span style=\"color: #cc3300;\">'\/'<\/span>](<span style=\"color: #ff6600;\">3.5<\/span>, <span style=\"color: #ff6600;\">4.5<\/span>) <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>In this example, I use a dispatch table (1) which maps characters to callables. A callable can be a function (1), a function object (2), or a function object created by <code>std::bind<\/code> (3), or a lambda function. The key point of <code>std::function<\/code> is that it accepts all different <em>function types<\/em> and erases their types. <code>std::function<\/code> requires from its callables that it takes two <code>double's<\/code> and returns a <code>double: std::function&lt;double(double, double)&gt;.<\/code><\/p>\n<p>To complete the example, here is the output.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5500\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/callable.png\" alt=\"callable\" width=\"350\" height=\"240\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/callable.png 379w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/callable-300x206.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>Before I write more about type erasure with templates in the next post, let me summarise the three techniques to implement type erasure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5501\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/TypeErasureCompare.png\" alt=\"TypeErasureCompare\" width=\"500\" height=\"122\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/TypeErasureCompare.png 954w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/TypeErasureCompare-300x73.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/TypeErasureCompare-768x187.png 768w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>You can implement type erasure with void pointers, object orientation, or templates. Only the implementation with templates is type-safe and doesn&#8217;t require a type hierarchy. The missing details of templates will follow.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>I assume you want to know how type erasure with templates is implemented. Of course, you have to wait for my<a href=\"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-type-erasure-with-templates\"> next post<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The rule &#8220;T.5: Combine generic and OO techniques to amplify their strengths, not their costs&#8221;&nbsp; of the core guidelines to generic programming uses type erasure as an example. Type erasure? Really! Of course, it takes me two posts to explain this advanced template technique.<\/p>\n","protected":false},"author":21,"featured_media":5497,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[372],"tags":[420],"class_list":["post-5502","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-modern-c","tag-type-erasure"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5502","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=5502"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5502\/revisions"}],"predecessor-version":[{"id":6814,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5502\/revisions\/6814"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5497"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5502"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5502"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5502"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}