{"id":5284,"date":"2017-07-08T08:24:10","date_gmt":"2017-07-08T08:24:10","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-interfaces-ii\/"},"modified":"2023-06-26T12:10:19","modified_gmt":"2023-06-26T12:10:19","slug":"c-core-guidelines-interfaces-ii","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-interfaces-ii\/","title":{"rendered":"C++ Core Guidelines: Interfaces II"},"content":{"rendered":"<p>Interfaces are a contract between a service provider and a service consumer. The C++ Core Guidelines have 20 rules to make them suitable because &#8220;interfaces is probably the most important single aspect of code organization&#8221;.<\/p>\n<p><!--more--><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5282\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/07\/Lego_dimensions.svg.png\" alt=\"Lego dimensions.svg\" width=\"600\" height=\"300\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/07\/Lego_dimensions.svg.png 800w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/07\/Lego_dimensions.svg-300x150.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/07\/Lego_dimensions.svg-768x384.png 768w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>I wrote <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-interfaces\">in my last post<\/a><a href=\"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-interfaces\"> <\/a>about the first ten rules. Today I will finish my job and write about the remaining ten rules.<\/p>\n<ul>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-explicit\">I.1: Make interfaces explicit<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-global\">I.2: Avoid global variables<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-singleton\">I.3: Avoid singletons<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-typed\">I.4: Make interfaces precisely and strongly typed<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-pre\">I.5: State preconditions (if any)<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-expects\">I.6: Prefer <code class=\"highlighter-rouge no-highlight\">Expects()<\/code> for expressing preconditions<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-post\">I.7: State postconditions<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-ensures\">I.8: Prefer <code class=\"highlighter-rouge no-highlight\">Ensures()<\/code> for expressing postconditions<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-concepts\">I.9: If an interface is a template, document its parameters using concepts<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-except\">I.10: Use exceptions to signal a failure to perform a required task<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-raw\">I.11: Never transfer ownership by a raw pointer (<code class=\"highlighter-rouge no-highlight\">T*<\/code>)<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-nullptr\">I.12: Declare a pointer that must not be null as <code class=\"highlighter-rouge no-highlight\">not_null<\/code><\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-array\">I.13: Do not pass an array as a single pointer<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-global-init\">I.22: Avoid complex initialization of global objects<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-nargs\">I.23: Keep the number of function arguments low<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-unrelated\">I.24: Avoid adjacent unrelated parameters of the same type<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-abstract\">I.25: Prefer abstract classes as interfaces to class hierarchies<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-abi\">I.26: If you want a cross-compiler ABI, use a C-style subset<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-pimpl\">I.27: For stable library ABI, consider the Pimpl idiom<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Ri-encapsulate\">I.30: Encapsulate rule violations<\/a><\/li>\n<\/ul>\n<p>Let&#8217;s dive directly into the details.<\/p>\n<h4><strong>I.11: Never transfer ownership by a raw pointer (T*)<\/strong><\/h4>\n<p>There is a conceptual issue with this 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%;\">X<span style=\"color: #555555;\">*<\/span> <span style=\"color: #cc00ff;\">compute<\/span>(args)    <span style=\"color: #0099ff; font-style: italic;\">\/\/ don't<\/span>\r\n{\r\n    X<span style=\"color: #555555;\">*<\/span> res <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">new<\/span> X{};\r\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ ...<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> res;\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Who deletes the pointer X? There are at least three alternatives to deal with the ownership problem:<\/p>\n<ul>\n<li>return the value, if possible<\/li>\n<li>use a smart pointer<\/li>\n<li>use <span style=\"font-family: courier new,courier;\">owner&lt;X*&gt;<\/span> from the <a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#S-gsl\">guideline support library<\/a> (GSL)<\/li>\n<\/ul>\n<h4><strong>I.12: Declare a pointer that must not be null as not_null<\/strong><\/h4>\n<p>What is the semantic difference between the three variations of the following function <span style=\"font-family: courier new,courier;\">length<\/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: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">length<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">char<\/span><span style=\"color: #555555;\">*<\/span> p);            <span style=\"color: #0099ff; font-style: italic;\">\/\/ it is not clear whether length(nullptr) is valid<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">length<\/span>(not_null<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">char<\/span><span style=\"color: #555555;\">*&gt;<\/span> p);  <span style=\"color: #0099ff; font-style: italic;\">\/\/ better: we can assume that p cannot be nullptr<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">length<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">char<\/span><span style=\"color: #555555;\">*<\/span> p);            <span style=\"color: #0099ff; font-style: italic;\">\/\/ we must assume that p can be nullptr<\/span>\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The intention of variations two and three of <span style=\"font-family: courier new,courier;\">length<\/span> is quite apparent. The second variation accepts only a non-null pointer; the third accepts a <span style=\"font-family: courier new,courier;\">nullptr<\/span>. You may have already guessed it. <span style=\"font-family: courier new,courier;\">not_null<\/span> if from the GSL.<\/p>\n<h4><strong>I.13: Do not pass an array as a single pointer<\/strong><\/h4>\n<p>Passing arrays as a single pointer is quite error-prone.<\/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;\">copy_n<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> T<span style=\"color: #555555;\">*<\/span> p, T<span style=\"color: #555555;\">*<\/span> q, <span style=\"color: #007788; font-weight: bold;\">int<\/span> n); <span style=\"color: #0099ff; font-style: italic;\">\/\/ copy from [p:p+n) to [q:q+n)<\/span>\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>What will happen if <span style=\"font-family: courier new,courier;\">n<\/span> is too big? Right: undefined behavior. The GSL offers a solution called spans.<\/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;\">copy<\/span>(span<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">const<\/span> T<span style=\"color: #555555;\">&gt;<\/span> r, span<span style=\"color: #555555;\">&lt;<\/span>T<span style=\"color: #555555;\">&gt;<\/span> r2); <span style=\"color: #0099ff; font-style: italic;\">\/\/ copy r to r2<\/span>\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Spans deduce their number of arguments.<\/p>\n<\/p>\n<h4><strong>I.22: Avoid complex initialization of global objects<\/strong><\/h4>\n<p>Global objects provide a lot of fun. For example, their initialization order is not defined if they are in different translation units. The following code snippet has undefined behavior.<\/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;\">\/\/ file1.c<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">extern<\/span> <span style=\"color: #006699; font-weight: bold;\">const<\/span> X x;\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">const<\/span> Y y <span style=\"color: #555555;\">=<\/span> f(x);   <span style=\"color: #0099ff; font-style: italic;\">\/\/ read x; write y<\/span>\r\n\r\n<span style=\"color: #0099ff; font-style: italic;\">\/\/ file2.c<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">extern<\/span> <span style=\"color: #006699; font-weight: bold;\">const<\/span> Y y;\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">const<\/span> X x <span style=\"color: #555555;\">=<\/span> g(y);   <span style=\"color: #0099ff; font-style: italic;\">\/\/ read y; write x<\/span>\r\n<\/pre>\n<\/div>\n<h4><strong>I.23: Keep the number of function arguments low<\/strong><\/h4>\n<p>There is a simple rule: one function should do exactly one job. If that is the case, the number of function arguments automatically becomes low, making the function easy to use.<\/p>\n<p>The <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-17-new-algorithm-of-the-standard-template-library\">New Parallel Algorithms of Standard Template Library<\/a>, such as <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/algorithm\/transform_reduce\">std::transform_reduce<\/a><span style=\"font-family: courier new,courier;\">,&nbsp;<\/span> often break this rule.<\/p>\n<h4><strong>I.24: Avoid adjacent unrelated parameters of the same type<\/strong><\/h4>\n<p>What are the source and the destination of the following <span style=\"font-family: courier new,courier;\">copy_n<\/span> function? Any educated guess?<\/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;\">copy_n<\/span>(T<span style=\"color: #555555;\">*<\/span> p, T<span style=\"color: #555555;\">*<\/span> q, <span style=\"color: #007788; font-weight: bold;\">int<\/span> n); \r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>I often have to look for documentation.<\/p>\n<h4><strong>I.25: Prefer abstract classes as interfaces to class hierarchies<\/strong><\/h4>\n<p>Of course, that is an evident and long-established rule for object-oriented design. The guidelines provide two reasons for this rule.<\/p>\n<ul>\n<li>abstract classes are more likely to be stable than base classes<\/li>\n<li>bases classes with state and non-abstract methods put more constraints on derived classes<\/li>\n<\/ul>\n<h4><strong>I.26: If you want a cross-compiler ABI, use a C-style subset<\/strong><\/h4>\n<p>ABI stands for <strong>A<\/strong>pplication <strong>B<\/strong>inary <strong>I<\/strong>nterface.<\/p>\n<p>This is a strange rule in C++ guidelines. The reason is that &#8220;Different compilers implement different binary layouts for classes, exception handling, function names, and other implementation details.&#8221;. On some platforms, common ABIs are emerging. Using a single compiler, you can stick to the full C++ interface. In this case, you have to recompile the code.<\/p>\n<h4><strong>I.27: For stable library ABI, consider the Pimpl idiom<\/strong><\/h4>\n<p>Pimpl stands for a pointer to implementation and is the C++ variation of the<a href=\"https:\/\/en.wikipedia.org\/wiki\/Bridge_pattern\"> bridge pattern<\/a>. The idea is that a non-polymorphic interface holds the pointer to its implementation. Therefore, modification of the implementation doesn&#8217;t require recompilation of the interface.<\/p>\n<p>Here is an example from the C++ Core Guidelines:<\/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%;\">interface (widget.h)\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">widget<\/span> {\r\n    <span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">impl<\/span>;\r\n    std<span style=\"color: #555555;\">::<\/span>unique_ptr<span style=\"color: #555555;\">&lt;<\/span>impl<span style=\"color: #555555;\">&gt;<\/span> pimpl;\r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">draw<\/span>(); <span style=\"color: #0099ff; font-style: italic;\">\/\/ public API that will be forwarded to the implementation<\/span>\r\n    widget(<span style=\"color: #007788; font-weight: bold;\">int<\/span>); <span style=\"color: #0099ff; font-style: italic;\">\/\/ defined in the implementation file<\/span>\r\n    <span style=\"color: #555555;\">~<\/span>widget();   <span style=\"color: #0099ff; font-style: italic;\">\/\/ defined in the implementation file, where impl is a complete type<\/span>\r\n    widget(widget<span style=\"color: #555555;\">&amp;&amp;<\/span>) <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">default<\/span>;\r\n    widget(<span style=\"color: #006699; font-weight: bold;\">const<\/span> widget<span style=\"color: #555555;\">&amp;<\/span>) <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">delete<\/span>;\r\n    widget<span style=\"color: #555555;\">&amp;<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">=<\/span>(widget<span style=\"color: #555555;\">&amp;&amp;<\/span>); <span style=\"color: #0099ff; font-style: italic;\">\/\/ defined in the implementation file<\/span>\r\n    widget<span style=\"color: #555555;\">&amp;<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">=<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> widget<span style=\"color: #555555;\">&amp;<\/span>) <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">delete<\/span>;\r\n};\r\n\r\nimplementation (widget.cpp)\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">widget<\/span><span style=\"color: #555555;\">::<\/span>impl {\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> n; <span style=\"color: #0099ff; font-style: italic;\">\/\/ private data<\/span>\r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">draw<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> widget<span style=\"color: #555555;\">&amp;<\/span> w) { <span style=\"color: #0099ff; font-style: italic;\">\/* ... *\/<\/span> }\r\n    impl(<span style=\"color: #007788; font-weight: bold;\">int<\/span> n) <span style=\"color: #555555;\">:<\/span> n(n) {}\r\n};\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> widget<span style=\"color: #555555;\">::<\/span>draw() { pimpl<span style=\"color: #555555;\">-&gt;<\/span>draw(<span style=\"color: #555555;\">*<\/span><span style=\"color: #006699; font-weight: bold;\">this<\/span>); }\r\nwidget<span style=\"color: #555555;\">::<\/span>widget(<span style=\"color: #007788; font-weight: bold;\">int<\/span> n) <span style=\"color: #555555;\">:<\/span> pimpl{std<span style=\"color: #555555;\">::<\/span>make_unique<span style=\"color: #555555;\">&lt;<\/span>impl<span style=\"color: #555555;\">&gt;<\/span>(n)} {}\r\nwidget<span style=\"color: #555555;\">::~<\/span>widget() <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">default<\/span>;\r\nwidget<span style=\"color: #555555;\">&amp;<\/span> widget<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">=<\/span>(widget<span style=\"color: #555555;\">&amp;&amp;<\/span>) <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">default<\/span>;\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The <span style=\"font-family: courier new,courier;\">pimpl<\/span> is the pointer that holds the handle to the implementation.<\/p>\n<p>For an in-depth discussion of this C++ idiom, read the <a href=\"https:\/\/herbsutter.com\/gotw\/_100\/\">GOTW #100<\/a> article by Herb Sutter. GotW stands f\u00fcr Guro of the Week.<\/p>\n<h4><strong>I.30: Encapsulate rule violations<\/strong><\/h4>\n<p>Sometimes code is ugly, unsafe, or error-prone because of various reasons. Put the code in one place and encapsulate it with an easy-to-use interface. That is called abstraction, which you sometimes have to do. I have no problem with that code if the internal code is stable and the interface only lets you use it correctly.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>I often mentioned the guideline support library in the last posts, including the current one. Now it&#8217;s time to look at insight, and I will write about it in the <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-core-guideline-the-guidelines-support-library\">next post<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Interfaces are a contract between a service provider and a service consumer. The C++ Core Guidelines have 20 rules to make them suitable because &#8220;interfaces is probably the most important single aspect of code organization&#8221;.<\/p>\n","protected":false},"author":21,"featured_media":5282,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[372],"tags":[477],"class_list":["post-5284","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-modern-c","tag-interfaces"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5284","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=5284"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5284\/revisions"}],"predecessor-version":[{"id":6805,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5284\/revisions\/6805"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5282"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5284"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5284"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5284"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}