{"id":729,"date":"2015-11-14T00:36:57","date_gmt":"2015-11-13T23:36:57","guid":{"rendered":"http:\/\/numbercrunch.de\/blog\/?p=729"},"modified":"2023-01-18T20:46:25","modified_gmt":"2023-01-18T19:46:25","slug":"revisiting-the-named-parameter-idiom-in-c14","status":"publish","type":"post","link":"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/","title":{"rendered":"Revisiting the named parameter idiom in C++14"},"content":{"rendered":"<p style=\"text-align: justify;\">Some programming languages have functions with named parameters. Named parameters let the programmer pass the parameters to a function in any order and they are distinguished by a name. So the programmer can explicitly pass all the needed parameters and default values without worrying about the order used in the function declaration. In C++, however, functions have positional arguments.\u00a0 This means, for functions with many parameters, the programmer has to remember the types and the order in which to pass them. Furthermore, default values can only be given to the last parameters, so it is not possible to specify one of the later parameters and use the default value for former ones.<\/p>\n<p style=\"text-align: justify;\">Named parameters might become a feature of <a href=\"http:\/\/www.open-std.org\/JTC1\/SC22\/WG21\/docs\/papers\/2014\/n4172.htm\" target=\"_blank\" rel=\"noopener\">future C++ versions<\/a> but can not jet be used directly in C++. Thus, C++ programmers have devised various techniques to emulate named parameters in C++, e.g., by using <a href=\"https:\/\/isocpp.org\/wiki\/faq\/ctors#named-parameter-idiom\" target=\"_blank\" rel=\"noopener\">method chaining<\/a>. C++14 offers some new features which allow implementations of named parameters with a very neat syntax, as I will demonstrate in the following. The presented implementation ensures that some possible errors, which might occur in the context of named parameters are detected at compile time.<\/p>\n<ul>\n<li style=\"text-align: justify;\">Each named parameter can be given only once per function call.<\/li>\n<li style=\"text-align: justify;\">Named parameters without a default value must be given.<\/li>\n<li style=\"text-align: justify;\">Only allowed named parameters can be passed to a function.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Let us have a look at a specific example how this implementation can be used. In this implementation, parameter names and values are represented by structures with a single data member <tt>value<\/tt>. In the following example these are <tt>name<\/tt>, <tt>buffersize<\/tt> and <tt>writemode<\/tt>. These structures are passed as anonymous objects, which are constructed via <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/language\/aggregate_initialization\" target=\"_blank\" rel=\"noopener\">aggregate initialization<\/a>, to a variadic template function, which forwards these function arguments (or the default values) in the correct order to the actual implementation by a standard function with a fixed number of positional arguments.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">#include &lt;iostream&gt;\n#include &lt;string&gt;\n#include \"named_parameter.hpp\"\n\n\/\/ some structures representing parameter names and values\nstruct name {\n  const std::string &amp;value;\n};\n\nstruct buffersize {\n  const int &amp;value;\n};\n\nstruct writemode {\n  const bool value;\n};\n\nconstexpr writemode writable{true};\nconstexpr writemode readonly{false};\n\nstruct invalid {\n  const int &amp;value;\n};\n\n\/\/ a function with many parameters\nvoid open_file_impl(const std::string &amp;name, int buffersize, bool writable) {\n  std::cout &lt;&lt; \"name       : \" &lt;&lt; name &lt;&lt; std::endl;\n  std::cout &lt;&lt; \"buffersize : \" &lt;&lt; buffersize &lt;&lt; std::endl;\n  std::cout &lt;&lt; \"writable   : \" &lt;&lt; writable &lt;&lt; std::endl;\n  std::cout &lt;&lt; std::endl;\n}\n\n\/\/ template function taking named parameters which\n\/\/ are passed to actual function implementation\ntemplate&lt;typename... Ts&gt;\nvoid open_file(const Ts &amp;...args) {\n  static_assert(named_para::is_valid&lt;named_para::parameter_set&lt;name, buffersize, writemode&gt;, Ts...&gt;(),\n                \"invalid named parameter argument\");\n  auto t=std::make_tuple(args...);\n  open_file_impl(named_para::get&lt;name&gt;(t),\n                 named_para::get&lt;buffersize&gt;(t, 1024),\n                 named_para::get&lt;writemode&gt;(t, false));\n}\n\nint main() {\n  open_file(name{\"file.dat\"});\n  open_file(buffersize{8192}, writable, name{\"file_name.dat\"});\n  open_file(readonly, name{\"another_file_name.dat\"});\n  \/\/ next line will not compile because of missing mandatory parameter\n  \/\/ open_file(buffersize{1234});\n  \/\/ next line will not compile because of invalid parameter\n  \/\/ open_file(buffersize{1234}, name{\"another_file_name.dat\"}, invalid{1});\n  \/\/ next line will not compile because of repeated parameter\n  \/\/ open_file(buffersize{1234}, name{\"another_file_name.dat\"}, name{\"foo\"});\n}\n<\/pre>\n<p>The implementation of the named parameters is given in the following header file. The whole magic of this implementation relies on the template class <tt>std::tuple<\/tt>, which allows in C++14 to access a specific element via its type by the function <tt>std::get<\/tt>, and variadic templates. In the application code as shown above, function arguments to the variadic template function are put into a <tt>std::tuple<\/tt> and the function <tt>named_para::get<\/tt> returns a desired function argument from the tuple or a possible default value if not present. In this way, named function arguments can be put into the right order to pass them to a function with positional arguments. In order to decide if the default argument has to be employed, it has to be checked if a certain type, which represents a parameter name, is present in the set of given arguments. This is accomplished by the template class <tt>has_type<\/tt>, which has either <tt>std::true<\/tt> or <tt>std::false<\/tt> as base class, depending on if the parameter name is present in the function call or not. Finally, the helper class <tt>is_valid<\/tt> can be used to check if a set of given parameter names contains only valid types (parameter names).<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">#ifndef NAMED_PARAMETER_HPP\n#define NAMED_PARAMETER_HPP\n\n#include &lt;tuple&gt;\n#include &lt;type_traits&gt;\n\nnamespace named_para {\n\n  \/\/ compile time check if type T is in tuple of type Tuple\n\u00a0 template&lt;typename T, typename Tuple&gt;\n\u00a0 struct has_type;\n\n  \/\/ empty tuple cannot contain T\n\u00a0 template&lt;typename T&gt;\n\u00a0 struct has_type&lt;T, std::tuple&lt;&gt;&gt; : std::false_type {\n\u00a0 };\n\n  \/\/ 1st type in tuple is not T, T may be in other elements\n\u00a0 template&lt;typename T, typename U, typename... Ts&gt;\n\u00a0 struct has_type&lt;T, std::tuple&lt;U, Ts...&gt;&gt; : has_type&lt;T, std::tuple&lt;Ts...&gt;&gt; {\n\u00a0 };\n\n  \/\/ 1st type in tuple is T, thus tuple contains an element of type T\n\u00a0 template&lt;typename T, typename... Ts&gt;\n\u00a0 struct has_type&lt;T, std::tuple&lt;T, Ts...&gt;&gt; : std::true_type {\n\u00a0 };\n\n  \/\/ compile time check if type pack Ts contains only valid types given in tuple\n\u00a0 template&lt;typename Tuple, typename... Ts&gt;\n\u00a0 class is_valid;\n\n  \/\/ check if T is in Tuple if type pack has only a single type T\n\u00a0 template&lt;typename Tuple, typename T&gt;\n\u00a0 struct is_valid&lt;Tuple, T&gt; : has_type&lt;T, Tuple&gt; {\n\u00a0 };\n\n  \/\/ recursive definition of is_valid\n  \/\/ type pack is valid if 1st element is valid and remaining types are valid\n\u00a0 template&lt;typename Tuple, typename T, typename... Ts&gt;\n\u00a0 struct is_valid&lt;Tuple, T, Ts...&gt; : std::integral_constant&lt;bool, is_valid&lt;Tuple, T&gt;() and is_valid&lt;Tuple, Ts...&gt;()&gt; {\n\u00a0 };\n\n\u00a0 template&lt;typename T, typename Tup, typename Enable=void&gt; \n\u00a0 class get_impl {\n\u00a0 public:\n    \/\/ type T not present in tupe, return default value\n\u00a0\u00a0\u00a0 static auto get(const Tup &amp;tup, const decltype(T::value) &amp;def) -&gt; decltype(T::value) {\n\u00a0\u00a0\u00a0\u00a0\u00a0 return def;\n\u00a0\u00a0\u00a0 }\n\u00a0 };\n\n\u00a0 template&lt;typename T, typename Tup&gt;\n\u00a0 class get_impl&lt;T, Tup, typename std::enable_if&lt;has_type&lt;T, Tup&gt;::value&gt;::type&gt; {\n\u00a0 public:\n    \/\/ type T present in tuple, return T::value from tuple, ignore 2nd parameter\n\u00a0\u00a0\u00a0 static auto get(const Tup &amp;tup, const decltype(T::value) &amp;) -&gt; decltype(T::value) {\n\u00a0\u00a0\u00a0\u00a0\u00a0 return std::get&lt;T&gt;(tup).value;\n\u00a0\u00a0\u00a0 }\n    \/\/ type T present in tuple, return T::value from tuple\n\u00a0\u00a0\u00a0 static auto get(const Tup &amp;tup) -&gt; decltype(T::value) {\n\u00a0\u00a0\u00a0\u00a0\u00a0 return std::get&lt;T&gt;(tup).value;\n\u00a0\u00a0\u00a0 }\n\u00a0 };\n\n  \/\/ get T::value if element of type T present in tuple or default parameter otherwise\n\u00a0 template&lt;typename T, typename Tup&gt;\n\u00a0 auto get(const Tup &amp;tup, const decltype(T::value) &amp;def) -&gt; decltype(get_impl&lt;T, Tup&gt;::get(tup, def)) {\n\u00a0\u00a0\u00a0 return get_impl&lt;T, Tup&gt;::get(tup, def);\n\u00a0 };\n\n  \/\/ get T::value from tuple\n\u00a0 template&lt;typename T, typename Tup&gt;\n\u00a0 auto get(const Tup &amp;tup) -&gt; decltype(get_impl&lt;T, Tup&gt;::get(tup)) {\n\u00a0\u00a0\u00a0 return get_impl&lt;T, Tup&gt;::get(tup);\n\u00a0 };\n\n\u00a0 template&lt;typename ...Ts&gt; using parameter_set = std::tuple&lt;Ts...&gt;;\n}\n\n#endif\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Some programming languages have functions with named parameters. Named parameters let the programmer pass the parameters to a function in any order and they are distinguished by a name. So the programmer can explicitly pass all the needed parameters and default values without worrying about the order used in the function declaration. In C++, however,&hellip; <a href=\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Revisiting the named parameter idiom in C++14<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16],"tags":[],"class_list":["post-729","post","type-post","status-publish","format-standard","hentry","category-c"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v25.6 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Revisiting the named parameter idiom in C++14 - Number Crunch<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Revisiting the named parameter idiom in C++14 - Number Crunch\" \/>\n<meta property=\"og:description\" content=\"Some programming languages have functions with named parameters. Named parameters let the programmer pass the parameters to a function in any order and they are distinguished by a name. So the programmer can explicitly pass all the needed parameters and default values without worrying about the order used in the function declaration. In C++, however,&hellip; Continue reading Revisiting the named parameter idiom in C++14\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/\" \/>\n<meta property=\"og:site_name\" content=\"Number Crunch\" \/>\n<meta property=\"article:published_time\" content=\"2015-11-13T23:36:57+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-01-18T19:46:25+00:00\" \/>\n<meta name=\"author\" content=\"Heiko Bauke\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Heiko Bauke\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/\"},\"author\":{\"name\":\"Heiko Bauke\",\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413\"},\"headline\":\"Revisiting the named parameter idiom in C++14\",\"datePublished\":\"2015-11-13T23:36:57+00:00\",\"dateModified\":\"2023-01-18T19:46:25+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/\"},\"wordCount\":522,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413\"},\"articleSection\":[\"C++\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/\",\"url\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/\",\"name\":\"Revisiting the named parameter idiom in C++14 - Number Crunch\",\"isPartOf\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#website\"},\"datePublished\":\"2015-11-13T23:36:57+00:00\",\"dateModified\":\"2023-01-18T19:46:25+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.numbercrunch.de\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Revisiting the named parameter idiom in C++14\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#website\",\"url\":\"https:\/\/www.numbercrunch.de\/blog\/\",\"name\":\"Number Crunch\",\"description\":\"A computational science blog.\",\"publisher\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.numbercrunch.de\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413\",\"name\":\"Heiko Bauke\",\"logo\":{\"@id\":\"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/image\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Revisiting the named parameter idiom in C++14 - Number Crunch","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/","og_locale":"en_US","og_type":"article","og_title":"Revisiting the named parameter idiom in C++14 - Number Crunch","og_description":"Some programming languages have functions with named parameters. Named parameters let the programmer pass the parameters to a function in any order and they are distinguished by a name. So the programmer can explicitly pass all the needed parameters and default values without worrying about the order used in the function declaration. In C++, however,&hellip; Continue reading Revisiting the named parameter idiom in C++14","og_url":"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/","og_site_name":"Number Crunch","article_published_time":"2015-11-13T23:36:57+00:00","article_modified_time":"2023-01-18T19:46:25+00:00","author":"Heiko Bauke","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Heiko Bauke","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/#article","isPartOf":{"@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/"},"author":{"name":"Heiko Bauke","@id":"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413"},"headline":"Revisiting the named parameter idiom in C++14","datePublished":"2015-11-13T23:36:57+00:00","dateModified":"2023-01-18T19:46:25+00:00","mainEntityOfPage":{"@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/"},"wordCount":522,"commentCount":0,"publisher":{"@id":"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413"},"articleSection":["C++"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/","url":"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/","name":"Revisiting the named parameter idiom in C++14 - Number Crunch","isPartOf":{"@id":"https:\/\/www.numbercrunch.de\/blog\/#website"},"datePublished":"2015-11-13T23:36:57+00:00","dateModified":"2023-01-18T19:46:25+00:00","breadcrumb":{"@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.numbercrunch.de\/blog\/2015\/11\/revisiting-the-named-parameter-idiom-in-c14\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.numbercrunch.de\/blog\/"},{"@type":"ListItem","position":2,"name":"Revisiting the named parameter idiom in C++14"}]},{"@type":"WebSite","@id":"https:\/\/www.numbercrunch.de\/blog\/#website","url":"https:\/\/www.numbercrunch.de\/blog\/","name":"Number Crunch","description":"A computational science blog.","publisher":{"@id":"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.numbercrunch.de\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/e73eab65b1721dd0c3d408edb887e413","name":"Heiko Bauke","logo":{"@id":"https:\/\/www.numbercrunch.de\/blog\/#\/schema\/person\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/posts\/729"}],"collection":[{"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/comments?post=729"}],"version-history":[{"count":13,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/posts\/729\/revisions"}],"predecessor-version":[{"id":956,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/posts\/729\/revisions\/956"}],"wp:attachment":[{"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/media?parent=729"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/categories?post=729"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.numbercrunch.de\/blog\/wp-json\/wp\/v2\/tags?post=729"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}