How to Use asio::redirect_disposition for Operation Redirection
asio::redirect_disposition is a completion-token adapter that captures the disposition (error code or exception pointer) from an asynchronous operation into a user-provided variable while forwarding remaining arguments to the original handler.
The redirect_disposition utility in the chriskohlhoff/asio repository provides a clean mechanism for intercepting operation outcomes without altering your handler's signature. This pattern is particularly useful when you need to inspect error conditions separately from your main completion logic or when integrating with existing code that expects error codes in specific variables.
What is asio::redirect_disposition?
asio::redirect_disposition acts as a completion token adapter that sits between an asynchronous operation and its handler. Unlike redirect_error, which throws or returns errors directly, redirect_disposition captures the first argument of a completion handler—typically an asio::error_code or std::exception_ptr—into a reference variable you provide.
The mechanism consists of three core components defined in include/asio/redirect_disposition.hpp:
redirect_disposition_t– A thin wrapper storing the original completion token and a reference to the destination variablepartial_redirect_disposition– A higher-order token that binds the destination variable, enabling the syntaxasio::redirect_disposition(my_error)(token)async_resultspecialization – Defined ininclude/asio/impl/redirect_disposition.hpp, this adapts the wrapper into a real handler for any async operation
How asio::redirect_disposition Works Internally
The Adapter Components
When you invoke asio::redirect_disposition(ec), the function returns a partial_redirect_disposition instance. When this partial token is later combined with a real completion token (such as asio::use_future or a custom handler), the operator() creates a redirect_disposition_t<CompletionToken, Disposition> holding both the original token and a reference to your variable.
asio::error_code ec;
auto token = asio::redirect_disposition(ec); // partial_redirect_disposition
auto wrapped = token(asio::use_future); // redirect_disposition_t
Handler Transformation
The async_result specialization for redirect_disposition_t constructs a detail::redirect_disposition_handler<Disposition, Handler> that intercepts the operation's completion. This handler:
- Stores a reference to the destination
Disposition& d_ - Holds the original handler (
Handler handler_) - Provides overloads of
operator()that forward arguments unchanged when the first argument is not aDisposition, or capture the first argument intod_when it is aDisposition
The implementation in include/asio/impl/redirect_disposition.hpp uses redirect_disposition_signature templates to rewrite the operation's completion signature, effectively removing the disposition argument from the user-visible signature while preserving the remaining parameters.
Exception Pointer Handling
When the destination type is std::exception_ptr, the handler automatically converts any disposition (such as an error_code) into an exception pointer via disposition_traits<>::to_exception_ptr. This allows uniform error handling regardless of the underlying error representation.
std::exception_ptr ep;
timer.async_wait(asio::redirect_disposition(ep));
Practical Examples
Capturing error_code
The most common use case involves capturing an asio::error_code into a variable for later inspection:
asio::io_context ctx;
asio::system_timer t(ctx, std::chrono::seconds(0));
asio::error_code ec = asio::error::would_block; // Pre-set to known state
t.async_wait(asio::redirect_disposition(ec));
ctx.run();
// After run(), ec contains the operation's error (or success code)
if (ec) {
std::cerr << "Timer error: " << ec.message() << "\n";
}
Capturing std::exception_ptr
For exception-based error handling, redirect to an std::exception_ptr:
std::exception_ptr ex;
t.async_wait(asio::redirect_disposition(ex));
t.cancel(); // Force an error
ctx.run();
// ex now holds a std::exception_ptr describing the aborted operation
if (ex) {
try {
std::rethrow_exception(ex);
} catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << "\n";
}
}
Combining with Custom Handlers
You can redirect the disposition while still using a custom completion handler:
struct my_handler {
void operator()(int) const {
std::cout << "Handler called with int argument\n";
}
};
asio::error_code ec;
t.async_wait(asio::redirect_disposition(
asio::bind_executor(ctx.get_executor(), my_handler()), ec));
Using with Deferred Tokens
The adapter works seamlessly with asio::deferred for composing asynchronous operations:
t.async_wait(asio::redirect_disposition(ec))(asio::deferred)([](int result) {
// Handle result here; error already captured in ec
});
Summary
asio::redirect_dispositioncaptures operation dispositions (error codes or exception pointers) into user-provided variables without altering handler signatures- The implementation relies on
redirect_disposition_t,partial_redirect_disposition, and specializedasync_resulttemplates found ininclude/asio/redirect_disposition.hppandinclude/asio/impl/redirect_disposition.hpp - The handler adapter automatically converts
error_codetostd::exception_ptrwhen the destination type requires it - This pattern enables flexible error handling when integrating with existing codebases or when you need to inspect errors separately from completion logic
Frequently Asked Questions
What is the difference between asio::redirect_disposition and asio::redirect_error?
asio::redirect_error modifies the completion signature to return the error code as a function result, while asio::redirect_disposition captures the error into a reference variable while keeping the rest of the handler signature intact. According to the source code in include/asio/impl/redirect_disposition.hpp, redirect_disposition is more flexible for cases where you want to capture the error but still receive other completion arguments in your handler.
Can I use asio::redirect_disposition with any asynchronous operation?
Yes, the async_result specialization in include/asio/impl/redirect_disposition.hpp makes redirect_disposition compatible with any Asio asynchronous operation that follows the standard completion token protocol. The adapter rewrites the completion signature using redirect_disposition_signature templates to ensure type safety regardless of the specific operation.
How does the exception_ptr conversion work in asio::redirect_disposition?
When the destination type is std::exception_ptr, the detail::redirect_disposition_handler automatically converts the disposition using disposition_traits<Disposition>::to_exception_ptr, as implemented in include/asio/impl/redirect_disposition.hpp. This allows you to capture operation failures as exception pointers even when the underlying operation reports errors via error_code.
Can I combine asio::redirect_disposition with other completion tokens like use_future?
Absolutely. The partial_redirect_disposition class provides an operator() that accepts any completion token, creating a redirect_disposition_t that wraps the original token. This means you can write asio::redirect_disposition(ec)(asio::use_future) to capture errors into ec while having the operation return a std::future for the remaining arguments.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →