C++26stlexpert
std::execution (Senders/Receivers) (C++26 Addition)
C++26 · The Next Frontier · Compiler flag: -std=c++26
Explanation
A structured asynchronous programming framework based on the senders/receivers model. Provides composable building blocks for expressing asynchronous workflows with clear ownership semantics, cancellation support, and error propagation. Replaces ad-hoc callback and future-based patterns with a unified, type-safe approach.
Real-World Scenario
Build a pipelined data processing system where stages (fetch, decode, transform, store) execute asynchronously and are composed declaratively.
Quick Snippet
snippet.cpp
#include <execution>
namespace ex = std::execution;
// Compose an async pipeline: schedule -> compute -> transform
auto work = ex::schedule(my_scheduler)
| ex::then([] { return fetch_data(); })
| ex::then([](auto data) { return process(data); });
// Execute synchronously for demonstration
auto result = ex::sync_wait(std::move(work));Full Example
execution.cpp
// CodeNebula - C++26 Example: std::execution Senders/Receivers Overview
// Compile: g++ -std=c++26 -Wall -Wextra -o example execution.cpp
// Note: Requires C++26 compiler support
#include <iostream>
#include <functional>
#include <string>
// C++26 introduces std::execution (P2300) — a framework for structured
// asynchronous programming built on three core abstractions:
//
// Scheduler - represents an execution context (thread pool, GPU, etc.)
// Sender - describes a unit of async work that produces values
// Receiver - consumes the result of a sender (value, error, or stopped)
//
// The model: scheduler.schedule() -> sender -> connect(receiver) -> operation
// sync_wait(sender) blocks until the sender completes.
// --- Educational simulation of the sender/receiver model ---
namespace exec_sim {
// A simple value sender: immediately completes with a value
template <typename T>
struct just_sender {
T value;
explicit just_sender(T v) : value(std::move(v)) {}
};
// Factory: creates a sender that holds a value
template <typename T>
just_sender<T> just(T value) { return just_sender<T>{std::move(value)}; }
// 'then' adaptor: chains a function onto a sender
template <typename S, typename F>
struct then_sender {
S inner;
F func;
};
template <typename S, typename F>
then_sender<S, F> then(S sender, F func) {
return {std::move(sender), std::move(func)};
}
// sync_wait: "runs" the sender chain and returns the result
template <typename T>
T sync_wait(just_sender<T> s) { return s.value; }
template <typename S, typename F>
auto sync_wait(then_sender<S, F> s) {
auto val = sync_wait(std::move(s.inner));
return s.func(val);
}
}
int main() {
// Build a sender pipeline (in real C++26: namespace ex = std::execution;)
auto work = exec_sim::then(
exec_sim::then(
exec_sim::just(10), // Start with value 10
[](int v) { return v * 2; } // Multiply by 2
),
[](int v) { return v + 5; } // Add 5
);
// Execute synchronously
int result = exec_sim::sync_wait(std::move(work));
std::cout << "Pipeline result: " << result << "\n";
// String pipeline
auto text = exec_sim::then(
exec_sim::just(std::string("hello")),
[](std::string s) { s += " world"; return s; }
);
std::cout << "Text result: " << exec_sim::sync_wait(std::move(text)) << "\n";
std::cout << "Sender/receiver model demonstrated successfully.\n";
return 0;
}
// Expected output:
// Pipeline result: 25
// Text result: hello world
// Sender/receiver model demonstrated successfully.
Run command
g++ -std=c++26 -Wall -Wextra -o example execution.cpp