Skip to content

Commit 5953eb3

Browse files
committed
asioexec::completion_token & ::use_sender: Constrain Initiate
Previously async_result<asioexec::completion_token, ...>:: and async_result<asioexec::use_sender, ...>::initiate: - Used automatic return type deduction, and - Were not constrained on any properties of the arguments thereto This meant that initiating functions of the form were problematic: template <typename AsyncReadStream, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadToken = default_completion_token_t< typename AsyncReadStream::executor_type>> inline auto async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, ReadToken&& token = default_completion_token_t< typename AsyncReadStream::executor_type>(), constraint_t< !is_completion_condition<ReadToken>::value > = 0) -> decltype( async_initiate<ReadToken, void (boost::system::error_code, std::size_t)>( declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(), token, basic_streambuf_ref<Allocator>(b), transfer_all())); Note that: - The above is an actual initiating function from Asio, and - The return type is defined in terms of the type returned by async_initiate The latter of the two points above means that the compiler must determine the type of an expression involving async_initiate. Since that expression transitively defers to async_result<...>::initiate this meant that the compiler had to determine the return type thereof. Since (as mentioned above) that function uses automatic return type deduction that meant the compiler had to substitute into the body thereof. Since errors in such a context are not SFINAE-friendly this meant that if the variadic pack of arguments thereto did not consist only of decay- copyable types there would be a hard compilation error (rather than the overload simply being removed from the candidate set). Both newly-added unit tests failed to compile before this change due to the above. Added a constraint to both previously-mentioned initiate functions to address the above.
1 parent 05edd1a commit 5953eb3

File tree

4 files changed

+39
-0
lines changed

4 files changed

+39
-0
lines changed

include/asioexec/completion_token.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ namespace ASIOEXEC_ASIO_NAMESPACE {
527527
template <typename... Signatures>
528528
struct async_result<::asioexec::completion_token_t, Signatures...> {
529529
template <typename Initiation, typename... Args>
530+
requires (std::is_constructible_v<std::decay_t<Args>, Args> && ...)
530531
static constexpr auto
531532
initiate(Initiation&& i, const ::asioexec::completion_token_t&, Args&&... args) {
532533
return ::asioexec::detail::completion_token::sender<

include/asioexec/use_sender.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ namespace ASIOEXEC_ASIO_NAMESPACE {
212212
template <typename... Signatures>
213213
struct async_result<::asioexec::use_sender_t, Signatures...> {
214214
template <typename Initiation, typename... Args>
215+
requires(std::is_constructible_v<std::decay_t<Args>, Args> && ...)
215216
static constexpr auto
216217
initiate(Initiation&& i, const ::asioexec::use_sender_t&, Args&&... args) {
217218
return ::asioexec::detail::use_sender::sender(

test/asioexec/test_completion_token.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,4 +997,25 @@ namespace {
997997
CHECK(ctx.stopped());
998998
}
999999

1000+
TEST_CASE(
1001+
"Substitution into async_result<completion_token, ...>::initiate is SFINAE-friendly",
1002+
"[asioexec][completion_token]") {
1003+
asio_impl::io_context ctx;
1004+
asio_impl::ip::tcp::socket socket(ctx);
1005+
asio_impl::streambuf buf;
1006+
// With a SFINAE-unfriendly async_result<...>::initiate the below line doesn't compile because there's a hard compilation error trying to consider the async_read overload for dynamic buffers
1007+
//
1008+
// See: https://github.com/NVIDIA/stdexec/issues/1684
1009+
auto sender = asio_impl::async_read(socket, buf, completion_token);
1010+
auto op = ::stdexec::connect(
1011+
std::move(sender) | ::stdexec::then([](const auto ec, const auto bytes_transferred) {
1012+
CHECK(ec);
1013+
CHECK(!bytes_transferred);
1014+
}),
1015+
expect_void_receiver{});
1016+
::stdexec::start(op);
1017+
CHECK(ctx.run() != 0);
1018+
CHECK(ctx.stopped());
1019+
}
1020+
10001021
} // namespace

test/asioexec/test_use_sender.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,4 +250,20 @@ namespace {
250250
CHECK(ctx.stopped());
251251
}
252252

253+
TEST_CASE(
254+
"Substitution into async_result<use_sender, ...>::initiate is SFINAE-friendly",
255+
"[asioexec][completion_token]") {
256+
asio_impl::io_context ctx;
257+
asio_impl::ip::tcp::socket socket(ctx);
258+
asio_impl::streambuf buf;
259+
// With a SFINAE-unfriendly async_result<...>::initiate the below line doesn't compile because there's a hard compilation error trying to consider the async_read overload for dynamic buffers
260+
//
261+
// See: https://github.com/NVIDIA/stdexec/issues/1684
262+
auto sender = asio_impl::async_read(socket, buf, use_sender);
263+
auto op = ::stdexec::connect(std::move(sender), expect_error_receiver{});
264+
::stdexec::start(op);
265+
CHECK(ctx.run() != 0);
266+
CHECK(ctx.stopped());
267+
}
268+
253269
} // namespace

0 commit comments

Comments
 (0)