diff --git a/include/asioexec/completion_token.hpp b/include/asioexec/completion_token.hpp index fe1cc2155..d5c63f94e 100644 --- a/include/asioexec/completion_token.hpp +++ b/include/asioexec/completion_token.hpp @@ -527,6 +527,7 @@ namespace ASIOEXEC_ASIO_NAMESPACE { template struct async_result<::asioexec::completion_token_t, Signatures...> { template + requires (std::is_constructible_v, Args> && ...) static constexpr auto initiate(Initiation&& i, const ::asioexec::completion_token_t&, Args&&... args) { return ::asioexec::detail::completion_token::sender< diff --git a/include/asioexec/use_sender.hpp b/include/asioexec/use_sender.hpp index 0ae7c148b..d0e67460e 100644 --- a/include/asioexec/use_sender.hpp +++ b/include/asioexec/use_sender.hpp @@ -212,6 +212,7 @@ namespace ASIOEXEC_ASIO_NAMESPACE { template struct async_result<::asioexec::use_sender_t, Signatures...> { template + requires(std::is_constructible_v, Args> && ...) static constexpr auto initiate(Initiation&& i, const ::asioexec::use_sender_t&, Args&&... args) { return ::asioexec::detail::use_sender::sender( diff --git a/test/asioexec/test_completion_token.cpp b/test/asioexec/test_completion_token.cpp index dd478e59b..fc6f0c56b 100644 --- a/test/asioexec/test_completion_token.cpp +++ b/test/asioexec/test_completion_token.cpp @@ -997,4 +997,25 @@ namespace { CHECK(ctx.stopped()); } + TEST_CASE( + "Substitution into async_result::initiate is SFINAE-friendly", + "[asioexec][completion_token]") { + asio_impl::io_context ctx; + asio_impl::ip::tcp::socket socket(ctx); + asio_impl::streambuf buf; + // 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 + // + // See: https://github.com/NVIDIA/stdexec/issues/1684 + auto sender = asio_impl::async_read(socket, buf, completion_token); + auto op = ::stdexec::connect( + std::move(sender) | ::stdexec::then([](const auto ec, const auto bytes_transferred) { + CHECK(ec); + CHECK(!bytes_transferred); + }), + expect_void_receiver{}); + ::stdexec::start(op); + CHECK(ctx.run() != 0); + CHECK(ctx.stopped()); + } + } // namespace diff --git a/test/asioexec/test_use_sender.cpp b/test/asioexec/test_use_sender.cpp index 08eb472be..69b9963a5 100644 --- a/test/asioexec/test_use_sender.cpp +++ b/test/asioexec/test_use_sender.cpp @@ -250,4 +250,20 @@ namespace { CHECK(ctx.stopped()); } + TEST_CASE( + "Substitution into async_result::initiate is SFINAE-friendly", + "[asioexec][completion_token]") { + asio_impl::io_context ctx; + asio_impl::ip::tcp::socket socket(ctx); + asio_impl::streambuf buf; + // 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 + // + // See: https://github.com/NVIDIA/stdexec/issues/1684 + auto sender = asio_impl::async_read(socket, buf, use_sender); + auto op = ::stdexec::connect(std::move(sender), expect_error_receiver{}); + ::stdexec::start(op); + CHECK(ctx.run() != 0); + CHECK(ctx.stopped()); + } + } // namespace