[exec.as.awaitable]/p2 has the following class declaration for the exposition-only sender-awaitable type:
template<class Sndr, class Promise>
class sender-awaitable {
struct unit {}; // exposition only
using value-type = // exposition only
single-sender-value-type<Sndr, env_of_t<Promise>>;
using result-type = // exposition only
conditional_t<is_void_v<value-type>, unit, value-type>;
struct awaitable-receiver; // exposition only
variant<monostate, result-type, exception_ptr> result{}; // exposition only
connect_result_t<Sndr, awaitable-receiver> state; // exposition only
public:
sender-awaitable(Sndr&& sndr, Promise& p);
static constexpr bool await_ready() noexcept { return false; }
void await_suspend(coroutine_handle<Promise>) noexcept { start(state); }
value-type await_resume();
};
In [exec.as.awaitable]/p2, CTAD is used to deduce the template parameters of sender-awaitable in the expressions sender-awaitable{adapted-expr, p} and sender-awaitable{expr, p}.
If decltype(expr) is a type Expr& (i.e., expr is an lvalue subexpression), then CTAD will deduce the type as sender-awaitable<Expr, Promise> and the expression sender-awaitable{expr, p} will be ill-formed because it is trying to bind an lvalue subexpression to an rvalue reference parameter.
The intention was that the template parameter Sndr would be deduced preserving the cv- and reference-qualification of the sender subexpression. In order to achieve that, we need to add a deduction guide.
Proposed Resolution
In [exec.as.awaitable]/p2, change the definition of sender-awaitable as follows:
template<class Sndr, class Promise>
class sender-awaitable {
struct unit {}; // exposition only
using value-type = // exposition only
single-sender-value-type<Sndr, env_of_t<Promise>>;
using result-type = // exposition only
conditional_t<is_void_v<value-type>, unit, value-type>;
struct awaitable-receiver; // exposition only
variant<monostate, result-type, exception_ptr> result{}; // exposition only
connect_result_t<Sndr, awaitable-receiver> state; // exposition only
public:
sender-awaitable(Sndr&& sndr, Promise& p);
static constexpr bool await_ready() noexcept { return false; }
void await_suspend(coroutine_handle<Promise>) noexcept { start(state); }
value-type await_resume();
};
template<class Sndr, class Promise>
sender-awaitable(Sndr&&, Promise&) -> sender-awaitable<Sndr, Promise>;
[exec.as.awaitable]/p2 has the following class declaration for the exposition-only
sender-awaitabletype:In [exec.as.awaitable]/p2, CTAD is used to deduce the template parameters of
sender-awaitablein the expressionssender-awaitable{adapted-expr, p}andsender-awaitable{expr, p}.If
decltype(expr)is a typeExpr&(i.e.,expris an lvalue subexpression), then CTAD will deduce the type assender-awaitable<Expr, Promise>and the expressionsender-awaitable{expr, p}will be ill-formed because it is trying to bind an lvalue subexpression to an rvalue reference parameter.The intention was that the template parameter
Sndrwould be deduced preserving the cv- and reference-qualification of the sender subexpression. In order to achieve that, we need to add a deduction guide.Proposed Resolution
In [exec.as.awaitable]/p2, change the definition of
sender-awaitableas follows:template<class Sndr, class Promise> class sender-awaitable { struct unit {}; // exposition only using value-type = // exposition only single-sender-value-type<Sndr, env_of_t<Promise>>; using result-type = // exposition only conditional_t<is_void_v<value-type>, unit, value-type>; struct awaitable-receiver; // exposition only variant<monostate, result-type, exception_ptr> result{}; // exposition only connect_result_t<Sndr, awaitable-receiver> state; // exposition only public: sender-awaitable(Sndr&& sndr, Promise& p); static constexpr bool await_ready() noexcept { return false; } void await_suspend(coroutine_handle<Promise>) noexcept { start(state); } value-type await_resume(); }; template<class Sndr, class Promise> sender-awaitable(Sndr&&, Promise&) -> sender-awaitable<Sndr, Promise>;