From 2957ffebf6b49ba7921af4fa196303be85581133 Mon Sep 17 00:00:00 2001 From: Robert Leahy Date: Tue, 8 Jul 2025 11:59:41 -0400 Subject: [PATCH] asioexec::completion_token: Lvalue Completion Handler Invocation As added by 35a3e31590e736fbb7dd55324b3a7f991a059ce3 the completion handler type used by the implementation of asioexec::completion_token only supported rvalue-qualified invocation. This was due to the fact: - Invocation of a completion handler is consumptive in the same way that calling set_value, set_error, or set_stopped on a receiver is (note those three operations require an rvalue-qualified operand), and - Asio has invoked completion handlers with rvalue qualification since 1.20.0 (standalone)/1.77 (Boost) Unfortunately there are operations in the wild which do not rvalue qualify their completion handlers when invoking them. For example the operations provided by Boost.Beast (at least as of this writing). Updated asioexec::completion_token to support the above-described operations by removing the rvalue qualification from the function call operator of its completion handler type. --- include/asioexec/completion_token.hpp | 2 +- test/asioexec/test_completion_token.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/asioexec/completion_token.hpp b/include/asioexec/completion_token.hpp index 193ae72aa..8068756fd 100644 --- a/include/asioexec/completion_token.hpp +++ b/include/asioexec/completion_token.hpp @@ -244,7 +244,7 @@ namespace asioexec { } template - void operator()(Args&&... args) && noexcept { + void operator()(Args&&... args) noexcept { STDEXEC_ASSERT(self_); { const std::lock_guard l(self_->m_); diff --git a/test/asioexec/test_completion_token.cpp b/test/asioexec/test_completion_token.cpp index af969d5ff..8d62154fc 100644 --- a/test/asioexec/test_completion_token.cpp +++ b/test/asioexec/test_completion_token.cpp @@ -718,4 +718,15 @@ namespace { CHECK(lvalue_kind == value_category_receiver::kind::const_lvalue); } + TEST_CASE( + "Lvalue invocation of the completion handler is supported (for compatibility with Boost.Beast " + "perhaps among others)", + "[asioexec][completion_token]") { + const auto initiating_function = [](auto&& token) { + return asio_impl::async_initiate([](auto&& h) { h(); }, token); + }; + auto op = ::stdexec::connect(initiating_function(completion_token), expect_value_receiver{}); + ::stdexec::start(op); + } + } // namespace