{"id":10481,"date":"2024-12-23T10:40:08","date_gmt":"2024-12-23T10:40:08","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=10481"},"modified":"2025-07-03T14:18:14","modified_gmt":"2025-07-03T14:18:14","slug":"stdexecution-more-senders","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/stdexecution-more-senders\/","title":{"rendered":"std::execution: More Senders"},"content":{"rendered":"\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"711\" height=\"491\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/12\/Timeexecution-1.png\" alt=\"\" class=\"wp-image-10449\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/12\/Timeexecution-1.png 711w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/12\/Timeexecution-1-300x207.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/12\/Timeexecution-1-705x487.png 705w\" sizes=\"auto, (max-width: 711px) 100vw, 711px\" \/><\/figure>\n\n\n\n<p><code>std::execution <\/code>offers three types of senders: factories, adapters, and consumers. I&#8217;ll take a closer look at these today. <\/p>\n\n\n\n<p>Most of the following content is from proposal <a href=\"https:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2024\/p2300r10.html\">P2300R10<\/a>. I will try to represent it more concisely.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Sender_Factory\"><\/span>Sender Factory<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>A sender factory is an algorithm<em> <\/em>that takes no senders as parameters and returns a sender. I already presented them in my last post:<code> <a href=\"https:\/\/www.modernescpp.com\/index.php\/stdexecution-sender\/\">std::execution: Sender<\/a><\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Sender_Adaptor\"><\/span>Sender Adaptor <span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>A sender adaptor is an algorithm that takes one or more senders as parameters and returns a sender.<\/p>\n\n\n\n<p>Sender adaptors are lazy. Sender consumers such as <code>this_thread::sync_wait <\/code>start senders.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"execution_let\"><\/span><code>execution::let_*<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\">execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> let_value(\n    execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> input,\n    std<span style=\"color: #555555\">::<\/span>invocable<span style=\"color: #555555\">&lt;<\/span>values<span style=\"color: #555555\">-<\/span>sent<span style=\"color: #555555\">-<\/span>by(input)...<span style=\"color: #555555\">&gt;<\/span> function\n);\n\nexecution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> let_error(\n    execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> input,\n    std<span style=\"color: #555555\">::<\/span>invocable<span style=\"color: #555555\">&lt;<\/span>errors<span style=\"color: #555555\">-<\/span>sent<span style=\"color: #555555\">-<\/span>by(input)...<span style=\"color: #555555\">&gt;<\/span> function\n);\n\nexecution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> let_stopped(\n    execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> input,\n    std<span style=\"color: #555555\">::<\/span>invocable <span style=\"color: #006699; font-weight: bold\">auto<\/span> function\n);\n<\/pre><\/div>\n\n\n\n<p><code>let_value<\/code> is very similar to <code>then<\/code>: when it is started, it invokes the provided function with the values sent by the input sender as arguments. However, where the sender returned from <code>then<\/code> sends exactly what that function ends up returning &#8211; <code>let_value<\/code> requires that the function return a sender, and the sender returned by <code>let_value<\/code> sends the values sent by the sender returned from the callback. <\/p>\n\n\n\n<p>A nice example about <code>let_value, let_error<\/code>, and <code>let_stopped<\/code> has the prototype library <a href=\"https:\/\/github.com\/NVIDIA\/stdexec\">stdexec<\/a>.<\/p>\n\n\n\n<p>The following example shows the main program of an HTTP server that handles multiple requests concurrently. (<a href=\"https:\/\/github.com\/NVIDIA\/stdexec\/blob\/main\/examples\/server_theme\/let_value.cpp\">https:\/\/github.com\/NVIDIA\/stdexec\/blob\/main\/examples\/server_theme\/let_value.cpp<\/a><a href=\"https:\/\/github.com\/NVIDIA\/stdexec\/blob\/main\/examples\/server_theme\/then_upon.cpp#L151\">)<\/a><\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #0099FF; font-style: italic\">\/*<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> * Copyright (c) 2022 Lucian Radu Teodorescu<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> *<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> * Licensed under the Apache License Version 2.0 with LLVM Exceptions<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> * (the &quot;License&quot;); you may not use this file except in compliance with<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> * the License. You may obtain a copy of the License at<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> *<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> *   https:\/\/llvm.org\/LICENSE.txt<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> *<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> * Unless required by applicable law or agreed to in writing, software<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> * See the License for the specific language governing permissions and<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> * limitations under the License.<\/span>\n<span style=\"color: #0099FF; font-style: italic\"> *\/<\/span>\n <span style=\"color: #007788; font-weight: bold\">int<\/span> <span style=\"color: #CC00FF\">main<\/span>() {\n  <span style=\"color: #0099FF; font-style: italic\">\/\/ Create a thread pool and get a scheduler from it<\/span>\n  exec<span style=\"color: #555555\">::<\/span>static_thread_pool pool{<span style=\"color: #FF6600\">8<\/span>};\n  ex<span style=\"color: #555555\">::<\/span>scheduler <span style=\"color: #006699; font-weight: bold\">auto<\/span> sched <span style=\"color: #555555\">=<\/span> pool.get_scheduler();\n\n  <span style=\"color: #0099FF; font-style: italic\">\/\/ Fake a couple of requests<\/span>\n  <span style=\"color: #006699; font-weight: bold\">for<\/span> (<span style=\"color: #007788; font-weight: bold\">int<\/span> i <span style=\"color: #555555\">=<\/span> <span style=\"color: #FF6600\">0<\/span>; i <span style=\"color: #555555\">&lt;<\/span> <span style=\"color: #FF6600\">10<\/span>; i<span style=\"color: #555555\">++<\/span>) {\n    <span style=\"color: #0099FF; font-style: italic\">\/\/ The whole flow for transforming incoming requests into responses<\/span>\n    ex<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> snd <span style=\"color: #555555\">=<\/span>\n      <span style=\"color: #0099FF; font-style: italic\">\/\/ get a sender when a new request comes<\/span>\n      schedule_request_start(sched, i)\n      <span style=\"color: #0099FF; font-style: italic\">\/\/ make sure the request is valid; throw if not<\/span>\n      <span style=\"color: #555555\">|<\/span> ex<span style=\"color: #555555\">::<\/span>let_value(validate_request)\n      <span style=\"color: #0099FF; font-style: italic\">\/\/ process the request in a function that may be using a different execution context<\/span>\n      <span style=\"color: #555555\">|<\/span> ex<span style=\"color: #555555\">::<\/span>let_value(handle_request)\n      <span style=\"color: #0099FF; font-style: italic\">\/\/ If there are errors transform them into proper responses<\/span>\n      <span style=\"color: #555555\">|<\/span> ex<span style=\"color: #555555\">::<\/span>let_error(error_to_response)\n      <span style=\"color: #0099FF; font-style: italic\">\/\/ If the flow is cancelled, send back a proper response<\/span>\n      <span style=\"color: #555555\">|<\/span> ex<span style=\"color: #555555\">::<\/span>let_stopped(stopped_to_response)\n      <span style=\"color: #0099FF; font-style: italic\">\/\/ write the result back to the client<\/span>\n      <span style=\"color: #555555\">|<\/span> ex<span style=\"color: #555555\">::<\/span>let_value(send_response)\n      <span style=\"color: #0099FF; font-style: italic\">\/\/ done<\/span>\n      ;\n\n    <span style=\"color: #0099FF; font-style: italic\">\/\/ execute the whole flow asynchronously<\/span>\n    ex<span style=\"color: #555555\">::<\/span>start_detached(std<span style=\"color: #555555\">::<\/span>move(snd));\n  }\n\n  pool.request_stop();\n\n  <span style=\"color: #006699; font-weight: bold\">return<\/span> <span style=\"color: #FF6600\">0<\/span>;\n}\n<\/pre><\/div>\n\n\n\n<p>An <code>exec::static_thread_pool pool <\/code>is created with 8 threads, and the <code>get_scheduler<\/code> method is called to obtain a scheduler object named <code>sched<\/code>.<\/p>\n\n\n\n<p>The program then simulates handling multiple requests by iterating over a loop 10 times. It constructs a pipeline of operations for each iteration to transform incoming requests into responses. An <code>ex::sender<\/code> <code>snd <\/code>represents this pipeline.<\/p>\n\n\n\n<p>The pipeline starts with the <code>schedule_request_start<\/code> function, which creates a sender that represents the start of handling a new request. The request is then validated using the <code>ex::let_value<\/code> function, which applies the <code>validate_request<\/code>. If the request is not valid, an exception is thrown.<\/p>\n\n\n\n<p>Next, the request is processed using the <code>ex::let_value<\/code> function that applies the handle_request function. If any errors occur during processing, they are transformed into proper responses using the <code>ex::let_error<\/code> function applying the<code> error_to_response <\/code>function. If the flow is cancelled, a proper response is sent back using the <code>ex::let_stopped <\/code>function applying the <code>stopped_to_response <\/code>function. Finally, the result is written back to the client using the <code>ex::let_value<\/code> function, which applies the <code>send_response<\/code> function.<\/p>\n\n\n\n<p>The <code>ex::start_detached<\/code> call detaches the execution from the current thread.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"execution_into_variant\"><\/span><code>execution::into_variant<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\">execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> into_variant(\n    execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> snd\n);\n<\/pre><\/div>\n\n\n\n<p>Returns a sender which sends a variant of tuples of all the possible sets of types sent by the input sender. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"execution_stopped_as_optional\"><\/span><code>execution::stopped_as_optional<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\">execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> stopped_as_optional(\n    single<span style=\"color: #555555\">-<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> snd\n);\n<\/pre><\/div>\n\n\n\n<p>Returns a sender that maps the value channel from a <code>T<\/code> to an <code>optional&lt;decay_t&lt;T&gt;&gt;<\/code>, and maps the stopped channel to a value of an empty <code>optional&lt;decay_t&lt;T&gt;&gt;<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"execution_stopped_as_error\"><\/span><code>execution::stopped_as_error<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #006699; font-weight: bold\">template<\/span><span style=\"color: #555555\">&lt;<\/span>move_constructible Error<span style=\"color: #555555\">&gt;<\/span>\nexecution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> stopped_as_error(\n    execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> snd,\n    Error err\n);\n<\/pre><\/div>\n\n\n\n<p>Returns a sender that maps the stopped channel to an error of <code>err<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"execution_bulk\"><\/span><code>execution::bulk<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\">execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> bulk(\n    execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> input,\n    std<span style=\"color: #555555\">::<\/span>integral <span style=\"color: #006699; font-weight: bold\">auto<\/span> shape,\n    invocable<span style=\"color: #555555\">&lt;<\/span>decltype(size), values<span style=\"color: #555555\">-<\/span>sent<span style=\"color: #555555\">-<\/span>by(input)...<span style=\"color: #555555\">&gt;<\/span> function\n);\n<\/pre><\/div>\n\n\n\n<p>Returns a sender that describes the callable <code>call<\/code> invoked on <code>input <\/code>according to <code>shape.<\/code><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"execution_split\"><\/span><code>execution::split<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\">execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> split(execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> sender);\n<\/pre><\/div>\n\n\n\n<p> If the provided sender is a multi-shot sender, return that sender. Otherwise, return a multi-shot sender that sends values equivalent to those sent by the provided sender. <\/p>\n\n\n\n<p>Some senders may only support launching their operation once, while others may be repeatable.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"execution_when_all\"><\/span><code>execution::when_all<\/code>*<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\">execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> when_all(\n    execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> ...inputs\n);\n\nexecution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> when_all_with_variant(\n    execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> ...inputs\n);\n<\/pre><\/div>\n\n\n\n<p><code>when_all<\/code> returns a sender that completes once all of the input senders have completed. <code>when_all_with_variant<\/code> does the same, but it adapts all the input senders using <code>into_variant<\/code>, and so it does not constrain the input arguments as <code>when_all<\/code> does.<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\">execution<span style=\"color: #555555\">::<\/span>scheduler <span style=\"color: #006699; font-weight: bold\">auto<\/span> sched <span style=\"color: #555555\">=<\/span> thread_pool.scheduler();\n\nexecution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> sends_1 <span style=\"color: #555555\">=<\/span> ...;\nexecution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> sends_abc <span style=\"color: #555555\">=<\/span> ...;\n\nexecution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> both <span style=\"color: #555555\">=<\/span> execution<span style=\"color: #555555\">::<\/span>when_all(\n    sends_1,\n    sends_abc\n);\n\nexecution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> final <span style=\"color: #555555\">=<\/span> execution<span style=\"color: #555555\">::<\/span>then(both, [](<span style=\"color: #006699; font-weight: bold\">auto<\/span>... args){\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> std<span style=\"color: #555555\">::<\/span>format(<span style=\"color: #CC3300\">&quot;the two args: {}, {}&quot;<\/span>, args...);\n});\n<span style=\"color: #0099FF; font-style: italic\">\/\/ when final executes, it will print &quot;the two args: 1, abc&quot;<\/span>\n<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Sender_Consumer\"><\/span>Sender Consumer <span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p><em>A sender consumer is an algorithm that takes one or more senders as parameters and does not return a sender.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"this_thread_sync_wait\"><\/span><code>this_thread::sync_wait<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #006699; font-weight: bold\">auto<\/span> sync_wait(\n    execution<span style=\"color: #555555\">::<\/span>sender <span style=\"color: #006699; font-weight: bold\">auto<\/span> sender\n) requires (always<span style=\"color: #555555\">-<\/span>sends<span style=\"color: #555555\">-<\/span>same<span style=\"color: #555555\">-<\/span>values(sender))\n    <span style=\"color: #555555\">-&gt;<\/span> std<span style=\"color: #555555\">::<\/span>optional<span style=\"color: #555555\">&lt;<\/span>std<span style=\"color: #555555\">::<\/span>tuple<span style=\"color: #555555\">&lt;<\/span>values<span style=\"color: #555555\">-<\/span>sent<span style=\"color: #555555\">-<\/span>by(sender)<span style=\"color: #555555\">&gt;&gt;<\/span>;\n<\/pre><\/div>\n\n\n\n<p><code>this_thread::sync_wait<\/code> is a sender consumer that submits the work described by the provided sender for execution, blocking <strong>the current <code>std::thread<\/code> or thread of <code>main<\/code><\/strong> until the work is completed, and returns an optional tuple of values sent by the provided sender on its completion of work. <code>sync_wait<\/code> is one way to <em>exit<\/em> the senders domain, retrieving the task graph result.<\/p>\n\n\n\n<p>If the provided sender sends an error instead of values, <code>sync_wait<\/code> throws that error as an exception, or rethrows the original exception if the error is of type <code>std::exception_ptr<\/code>.<\/p>\n\n\n\n<p>If the provided sender sends the &#8220;stopped&#8221; signal instead of values, <code>sync_wait<\/code> returns an empty optional.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"A_Short_Christmas_Break\"><\/span>A Short Christmas Break<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>I will take a two-week Christmas break. My next post will be published on January 13th.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>std::execution offers three types of senders: factories, adapters, and consumers. I&#8217;ll take a closer look at these today. Most of the following content is from proposal P2300R10. I will try to represent it more concisely. Sender Factory A sender factory is an algorithm that takes no senders as parameters and returns a sender. I already [&hellip;]<\/p>\n","protected":false},"author":21,"featured_media":10445,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[559],"tags":[561],"class_list":["post-10481","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c26-blog","tag-execution"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10481","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=10481"}],"version-history":[{"count":16,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10481\/revisions"}],"predecessor-version":[{"id":10522,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10481\/revisions\/10522"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/10445"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=10481"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=10481"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=10481"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}