short

Hello, sender: your first std::execution pipeline

· english· audience: working-cpp· AI-generated, reviewed by Filip Sajdak

C++26 has three tentpole features. Two of them, reflection and contracts, have had most of our attention. The third is std::execution: senders, receivers, and schedulers (P2300), the standard model for asynchronous and parallel work. It is the one a typical service codebase will touch first, and it is the least talked about. This post is the smallest program that shows what a sender actually is.

The program

#include <stdexec/execution.hpp>
#include <print>

int main() {
    // Build a lazy pipeline: produce 21, then double it.
    auto work = stdexec::just(21)
              | stdexec::then([](int x) { return x * 2; });

    // Drive it to completion on this thread; unwrap the single result.
    auto [result] = stdexec::sync_wait(work).value();

    std::println("doubled = {}", result);
}

Output:

doubled = 42

What just happened

A sender is a lazy description of asynchronous work, not the work itself. just(21) is a sender that will, when run, produce the value 21. then(f) is an adaptor: it takes a sender and returns a new sender that runs f on the value. The operator| chains them, the same way ranges pipe a view through adaptors.

Nothing has executed yet. The whole work object is a value you can pass around, store, or compose further. It only runs when something drives it: sync_wait runs the pipeline to completion on the calling thread and hands back the result (wrapped in an optional-like tuple, because a sender can also complete with an error or a cancellation instead of a value).

That laziness is what lets you keep composing before anything runs. A std::future is eager and one-shot: the work is already running and you can only .get() it once. A sender is a recipe you can keep building on before anyone lights the stove. The next post does exactly that.

A note on compilers

The std::execution wording is in C++26, but the shipping standard-library headers (<execution>’s sender machinery) are not yet in libstdc++ or libc++ as of June 2026. The example above uses NVIDIA’s stdexec, the reference implementation the standard text was distilled from. The namespaces map one-to-one onto std::execution, so this code is what the standard spelling will be. On Compiler Explorer the stdexec library is one dropdown entry away; the buttons below wire it in for you.

Where to next

One value through one adaptor is the “hello world.” The reason senders exist is composition: running several pieces of work concurrently and joining them without touching a mutex. That is the next short.