This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4357. connect-awaitable should use is_void_v to check for result-type of co_await expression instead of same_as<void>

Section: 33.9.10 [exec.connect] Status: New Submitter: Lewis Baker Opened: 2025-08-27 Last modified: 2025-09-14

Priority: Not Prioritized

View other active issues in [exec.connect].

View all other issues in [exec.connect].

View all issues with New status.

Discussion:

The wording in 33.9.10 [exec.connect] p5 defines the connect-awaitable() function as follows:

operation-state-task connect-awaitable(DS sndr, DR rcvr) requires receiver_of<DR, Sigs> {
  exception_ptr ep;
  try {
    if constexpr (same_as<V, void>) {
      co_await std::move(sndr);
      co_await suspend-complete(set_value, std::move(rcvr));
    } else {
      co_await suspend-complete(set_value, std::move(rcvr), co_await std::move(sndr));
    }
  } catch(...) {
    ep = current_exception();
  }
  co_await suspend-complete(set_error, std::move(rcvr), std::move(ep));
}

The use of same_as<V, void> in the if-constexpr condition does not cover the case where the result of the co_await expression has type cv void. It should use is_void_v<V> instead to allow it to match all void types, not just unqualified void.

Proposed resolution:

This wording is relative to N5014.

  1. Modify 33.9.10 [exec.connect] as indicated:

    -5- Let V name the type await-result-type<DS, connect-awaitable-promise>, let Sigs name the type

    completion_signatures<
      SET-VALUE-SIG(V), // see 33.9.3 [exec.snd.concepts]
      set_error_t(exception_ptr),
      set_stopped_t()>
    

    and let connect-awaitable be an exposition-only coroutine defined as follows:

    namespace std::execution {
      […]
      operation-state-task connect-awaitable(DS sndr, DR rcvr) requires receiver_of<DR, Sigs> {
        exception_ptr ep;
        try {
          if constexpr (same_as<V, void>is_void_v<V>) {
            co_await std::move(sndr);
            co_await suspend-complete(set_value, std::move(rcvr));
          } else {
            co_await suspend-complete(set_value, std::move(rcvr), co_await std::move(sndr));
          }
        } catch(...) {
          ep = current_exception();
        }
        co_await suspend-complete(set_error, std::move(rcvr), std::move(ep));
      }
    }