{"id":5659,"date":"2019-04-04T17:01:06","date_gmt":"2019-04-04T17:01:06","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-insights-variadic-templates\/"},"modified":"2019-04-04T17:01:06","modified_gmt":"2019-04-04T17:01:06","slug":"c-insights-variadic-templates","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-insights-variadic-templates\/","title":{"rendered":"C++ Insights &#8211; Variadic Templates"},"content":{"rendered":"<p>Variadic templates are a C++ feature that looks quite magic the first time you see them. Thanks to C++ Insights, most of the magic disappears.&nbsp;<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5658\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/04\/04-variadic-templates.png\" alt=\"04 variadic templates\" width=\"600\" height=\"338\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/04\/04-variadic-templates.png 1280w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/04\/04-variadic-templates-300x169.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/04\/04-variadic-templates-1024x576.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/04\/04-variadic-templates-768x432.png 768w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>Variadic templates are one of the powerful new constructs we have since C++11.<\/p>\n<h2>Variadic Templates<\/h2>\n<p>They are great because we can have a function that takes multiple arguments and still is strongly typed. We do not need a format specifier to cast some memory from the stack into a type. Variadic templates or in this case more precisely variadic function templates, expand into functions as we would write them. The so-called parameter pack gets expanded. During this process, each parameter is simply separated by a comma, just like we would write the function. Here is a basic example:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-keyword\">template<\/span>&lt;<span class=\"hljs-keyword\">typename<\/span> T&gt;\r\n<span class=\"hljs-function\">T <span class=\"hljs-title\">add<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">const<\/span> T&amp; arg)<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">return<\/span> arg;\r\n}\r\n\r\n<span class=\"hljs-keyword\">template<\/span>&lt;<span class=\"hljs-keyword\">typename<\/span> T, <span class=\"hljs-keyword\">typename<\/span>... ARGS&gt;\r\n<span class=\"hljs-function\">T <span class=\"hljs-title\">add<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">const<\/span> T&amp; arg, <span class=\"hljs-keyword\">const<\/span> ARGS&amp;... args)<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">return<\/span> arg + add(args...);\r\n}\r\n\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">return<\/span> add(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">2u<\/span>, <span class=\"hljs-number\">3u<\/span>);\r\n}\r\n<\/code><\/pre>\n<p>The single argument overload is required to terminate the recursion I used here. Let\u2019s use C++ Insights to see what\u2019s going on under the <a href=\"https:\/\/cppinsights.io\/lnk?code=dGVtcGxhdGU8dHlwZW5hbWUuLi4gQVJHUz4KYXV0byBhZGQoY29uc3QgQVJHUyYuLi4gYXJncykKewogIHJldHVybiAoYXJncyArIC4uLik7Cn0KCmludCBtYWluKCkKewogIHJldHVybiBhZGQoMSwgMnUsIDN1KTsKfQ==&amp;rev=1.0\">hood<\/a>:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-keyword\">template<\/span>&lt;<span class=\"hljs-keyword\">typename<\/span> T&gt;\r\n<span class=\"hljs-function\">T <span class=\"hljs-title\">add<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">const<\/span> T&amp; arg)<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">return<\/span> arg;\r\n}\r\n\r\n<span class=\"hljs-comment\">\/* First instantiated from: insights.cpp:10 *\/<\/span>\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">ifdef<\/span> INSIGHTS_USE_TEMPLATE<\/span>\r\n<span class=\"hljs-keyword\">template<\/span>&lt;&gt;\r\n<span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span> add&lt;<span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span>&gt;(<span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span> &amp; arg)\r\n{\r\n  <span class=\"hljs-keyword\">return<\/span> arg;\r\n}\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">endif<\/span><\/span>\r\n\r\n\r\n<span class=\"hljs-keyword\">template<\/span>&lt;<span class=\"hljs-keyword\">typename<\/span> T, <span class=\"hljs-keyword\">typename<\/span>... ARGS&gt;\r\n<span class=\"hljs-function\">T <span class=\"hljs-title\">add<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">const<\/span> T&amp; arg, <span class=\"hljs-keyword\">const<\/span> ARGS&amp;... args)<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">return<\/span> arg + add(args...);\r\n}\r\n\r\n<span class=\"hljs-comment\">\/* First instantiated from: insights.cpp:15 *\/<\/span>\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">ifdef<\/span> INSIGHTS_USE_TEMPLATE<\/span>\r\n<span class=\"hljs-keyword\">template<\/span>&lt;&gt;\r\n<span class=\"hljs-keyword\">int<\/span> add&lt;<span class=\"hljs-keyword\">int<\/span>, <span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span>, <span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span>&gt;(<span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">int<\/span> &amp; arg, <span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span> &amp; __args1, <span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span> &amp; __args2)\r\n{\r\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">static_cast<\/span>&lt;<span class=\"hljs-keyword\">int<\/span>&gt;(<span class=\"hljs-keyword\">static_cast<\/span>&lt;<span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span>&gt;(arg) + add(__args1, __args2));\r\n}\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">endif<\/span><\/span>\r\n\r\n\r\n<span class=\"hljs-comment\">\/* First instantiated from: insights.cpp:10 *\/<\/span>\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">ifdef<\/span> INSIGHTS_USE_TEMPLATE<\/span>\r\n<span class=\"hljs-keyword\">template<\/span>&lt;&gt;\r\n<span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span> add&lt;<span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span>, <span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span>&gt;(<span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span> &amp; arg, <span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">unsigned<\/span> <span class=\"hljs-keyword\">int<\/span> &amp; __args1)\r\n{\r\n  <span class=\"hljs-keyword\">return<\/span> arg + add(__args1);\r\n}\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">endif<\/span><\/span>\r\n\r\n\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">return<\/span> add(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">2u<\/span>, <span class=\"hljs-number\">3u<\/span>);\r\n}\r\n<\/code><\/pre>\n<p>Pay attention to the types. I used <code>2u<\/code> and <code>3u<\/code> which results in two <code>unsigned int<\/code> arguments and one <code>signed int<\/code>. Due to the arrangement of the parameters the return type&nbsp;&nbsp;<code>add<\/code> is <code>int<\/code> which leads, as C++ Insights shows the use, to an implicit cast in <code>add<\/code>. One additional insight C++ Insights shows us.<\/p>\n<\/p>\n<h3>Fold Expressions<\/h3>\n<p>With C++17 and fold-expressions we can reduce our code to this:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-keyword\">template<\/span>&lt;<span class=\"hljs-keyword\">typename<\/span>... ARGS&gt;\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">auto<\/span> <span class=\"hljs-title\">add<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">const<\/span> ARGS&amp;... args)<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">return<\/span> (args + ...);\r\n}\r\n\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">()<\/span>\r\n<\/span>{\r\n  <span class=\"hljs-keyword\">return<\/span> add(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">2u<\/span>, <span class=\"hljs-number\">3u<\/span>);\r\n}\r\n<\/code><\/pre>\n<p>I really like how the new standards make us write less and less code. The result of <a href=\"https:\/\/cppinsights.io\/lnk?code=dGVtcGxhdGU8dHlwZW5hbWUuLi4gQVJHUz4KYXV0byBhZGQoY29uc3QgQVJHUyYuLi4gYXJncykKewogIHJldHVybiAoYXJncyArIC4uLik7Cn0KCmludCBtYWluKCkKewogIHJldHVybiBhZGQoMSwgMnUsIDN1KTsKfQ==&amp;rev=1.0\">C++ Insights<\/a> changes as well:<\/p>\n<pre><code class=\"language-C+++\">template&lt;typename... ARGS&gt;\r\nauto add(const ARGS&amp;... args)\r\n{\r\n  return (args + ...);\r\n}\r\n\r\n\/* First instantiated from: insights.cpp:9 *\/\r\n#ifdef INSIGHTS_USE_TEMPLATE\r\ntemplate&lt;&gt;\r\nunsigned int add&lt;int, unsigned int, unsigned int&gt;(const int &amp; __args0, const unsigned int &amp; __args1, const unsigned int &amp; __args2)\r\n{\r\n  return static_cast&lt;unsigned int&gt;(__args0) + __args1 + __args2;\r\n}\r\n#endif\r\n\r\n\r\nint main()\r\n{\r\n  return static_cast&lt;int&gt;(add(1, 2u, 3u));\r\n}\r\n<\/code><\/pre>\n<p>Of course, you can write variadic class templates as well. Have a look at this code sample:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-keyword\">template<\/span>&lt;<span class=\"hljs-keyword\">int<\/span>...&gt;\r\n<span class=\"hljs-keyword\">struct<\/span> add;\r\n\r\n<span class=\"hljs-keyword\">template<\/span>&lt;&gt;\r\n<span class=\"hljs-keyword\">struct<\/span> add&lt;&gt;\r\n{\r\n  <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">constexpr<\/span> <span class=\"hljs-keyword\">int<\/span> value = <span class=\"hljs-number\">0<\/span>;\r\n};\r\n\r\n<span class=\"hljs-keyword\">template<\/span>&lt;<span class=\"hljs-keyword\">int<\/span> i, <span class=\"hljs-keyword\">int<\/span>... tail&gt;\r\n<span class=\"hljs-keyword\">struct<\/span> add&lt;i, tail...&gt;\r\n{\r\n  <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">constexpr<\/span> <span class=\"hljs-keyword\">int<\/span> value = i + add&lt;tail...&gt;::value;\r\n};\r\n\r\n<span class=\"hljs-keyword\">static_assert<\/span>(<span class=\"hljs-number\">6<\/span> == add&lt;<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">3<\/span>&gt;::value, <span class=\"hljs-string\">\"Expect 6\"<\/span>);\r\n<\/code><\/pre>\n<p>We have a variadic class template that calculates the sum of an arbitrary amount of numbers. C++ Insights shows all the instantiations that happen in the background to calculate the result. Here we can see how it pops one number each time until there are no more left:<\/p>\n<pre><code class=\"language-C++\"><span class=\"hljs-keyword\">template<\/span>&lt;<span class=\"hljs-keyword\">int<\/span>...&gt;\r\n<span class=\"hljs-keyword\">struct<\/span> add;\r\n\r\n<span class=\"hljs-comment\">\/* First instantiated from: insights.cpp:16 *\/<\/span>\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">ifdef<\/span> INSIGHTS_USE_TEMPLATE<\/span>\r\n<span class=\"hljs-keyword\">template<\/span>&lt;&gt;\r\n<span class=\"hljs-keyword\">struct<\/span> add&lt;<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">3<\/span>&gt;\r\n{\r\n  <span class=\"hljs-keyword\">inline<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">constexpr<\/span> <span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">int<\/span> value = <span class=\"hljs-number\">1<\/span> + add&lt;<span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">3<\/span>&gt;::value;\r\n  \r\n};\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">endif<\/span><\/span>\r\n\r\n\r\n<span class=\"hljs-comment\">\/* First instantiated from: insights.cpp:13 *\/<\/span>\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">ifdef<\/span> INSIGHTS_USE_TEMPLATE<\/span>\r\n<span class=\"hljs-keyword\">template<\/span>&lt;&gt;\r\n<span class=\"hljs-keyword\">struct<\/span> add&lt;<span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">3<\/span>&gt;\r\n{\r\n  <span class=\"hljs-keyword\">inline<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">constexpr<\/span> <span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">int<\/span> value = <span class=\"hljs-number\">2<\/span> + add&lt;<span class=\"hljs-number\">3<\/span>&gt;::value;\r\n  \r\n};\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">endif<\/span><\/span>\r\n\r\n\r\n<span class=\"hljs-comment\">\/* First instantiated from: insights.cpp:13 *\/<\/span>\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">ifdef<\/span> INSIGHTS_USE_TEMPLATE<\/span>\r\n<span class=\"hljs-keyword\">template<\/span>&lt;&gt;\r\n<span class=\"hljs-keyword\">struct<\/span> add&lt;<span class=\"hljs-number\">3<\/span>&gt;\r\n{\r\n  <span class=\"hljs-keyword\">inline<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">constexpr<\/span> <span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">int<\/span> value = <span class=\"hljs-number\">3<\/span> + add&lt;&gt;::value;\r\n  \r\n};\r\n<span class=\"hljs-preprocessor\">#<span class=\"hljs-keyword\">endif<\/span><\/span>\r\n\r\n\r\n<span class=\"hljs-keyword\">template<\/span>&lt;&gt;\r\n<span class=\"hljs-keyword\">struct<\/span> add&lt;&gt;\r\n{\r\n  <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">constexpr<\/span> <span class=\"hljs-keyword\">int<\/span> value = <span class=\"hljs-number\">0<\/span>;\r\n};\r\n\r\n<span class=\"hljs-keyword\">template<\/span>&lt;<span class=\"hljs-keyword\">int<\/span> i, <span class=\"hljs-keyword\">int<\/span>... tail&gt;\r\n<span class=\"hljs-keyword\">struct<\/span> add&lt;i, tail...&gt;\r\n{\r\n  <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">constexpr<\/span> <span class=\"hljs-keyword\">int<\/span> value = i + add&lt;tail...&gt;::value;\r\n};\r\n\r\n<span class=\"hljs-comment\">\/* PASSED: static_assert(6 == add&lt;1, 2, 3&gt;::value, \"Expect 6\"); *\/<\/span>\r\n<\/code><\/pre>\n<h2>Reference to an Array<\/h2>\n<p>One more thing about templates is that they can take a reference to an array which prevents an array from decaying to a pointer:<\/p>\n<pre><code class=\"language-C++\">template&lt;typename T, int N&gt;\r\nvoid Rx(T (&amp;data)[N])\r\n{\r\n  \/\/ assuming char here\r\n  static_assert(sizeof(data) == 5);\r\n}\r\n\r\nint main()\r\n{\r\n    char buffer[5]{};\r\n\r\n    Rx(buffer);\r\n}\r\n<\/code><\/pre>\n<p>In C++ Insights you can see that the instantiation contains the type as well as the size of the <a href=\"https:\/\/cppinsights.io\/lnk?code=dGVtcGxhdGU8dHlwZW5hbWUgVCwgaW50IE4+CnZvaWQgUngoVCAoJmRhdGEpW05dKQp7CiAgLy8gYXNzdW1pbmcgY2hhciBoZXJlCiAgc3RhdGljX2Fzc2VydChzaXplb2YoZGF0YSkgPT0gNSk7Cn0KCmludCBtYWluKCkKewogICAgY2hhciBidWZmZXJbNV17fTsKCiAgICBSeChidWZmZXIpOwp9&amp;std=cpp17&amp;rev=1.0\">array<\/a>:<\/p>\n<pre><code class=\"language-C++\">template&lt;typename T, int N&gt;\r\nvoid Rx(T (&amp;data)[N])\r\n{\r\n  \/\/ assuming char here\r\n  static_assert(sizeof(data) == 5);\r\n}\r\n\r\n\/* First instantiated from: insights.cpp:12 *\/\r\n#ifdef INSIGHTS_USE_TEMPLATE\r\ntemplate&lt;&gt;\r\nvoid Rx&lt;char, 5&gt;(char (&amp;data)[5])\r\n{\r\n  \/* PASSED: static_assert(sizeof(data) == 5); *\/\r\n}\r\n#endif\r\n\r\n\r\nint main()\r\n{\r\n  char buffer[5] = {'\\0', '\\0', '\\0', '\\0', '\\0'};\r\n  Rx(buffer);\r\n}\r\n<\/code><\/pre>\n<p>Another thing, aside from templates, you can see in this example the effect of braced initialization of buffer. The compiler fills all elements of the array for us with the default value. This means that we can say goodbye to the good old <code>memset<\/code> and make our programs faster and safer.<\/p>\n<p>I hope I could show you how C++ Insights can be helpful if it comes to templates. For me, it is a vital instrument when teaching and explaining templates, especially variadic templates. Try it out and tell me about your experience.<\/p>\n<p>I\u2019d like to thank Rainer for the opportunity to share information about C++ Insights on his popular blog!<\/p>\n<p>Have fun with C++ Insights. You can support the project by becoming a <a href=\"https:\/\/www.patreon.com\/cppinsights\">Patreon<\/a> or of course with code <a href=\"https:\/\/github.com\/andreasfertig\/cppinsights\">contributions<\/a>.<\/p>\n<p>Stay tuned for more insights about C++ Insight &#8230; . The next post is about lambdas.<\/p>\n<p><strong>Andreas<\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Variadic templates are a C++ feature that looks quite magic the first time you see them. Thanks to C++ Insights, most of the magic disappears.&nbsp;<\/p>\n","protected":false},"author":21,"featured_media":5658,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[374],"tags":[],"class_list":["post-5659","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cppinsight"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5659","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=5659"}],"version-history":[{"count":0,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5659\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5658"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5659"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5659"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5659"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}