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.

4363. transform_sender comparing types ignoring cv-qualifiers doesn't take into account differences in value category

Section: 33.9.6 [exec.snd.transform] Status: New Submitter: Lewis Baker Opened: 2025-08-28 Last modified: 2025-09-15

Priority: Not Prioritized

View all issues with New status.

Discussion:

In 33.9.6 [exec.snd.transform] p1, the specification for transform_sender() states:

Let transformed-sndr be the expression

dom.transform_sender(std::forward<Sndr>(sndr), env...)

if that expression is well-formed; otherwise,

default_domain().transform_sender(std::forward<Sndr>(sndr), env...)

Let final-sndr be the expression transformed-sndr if transformed-sndr and sndr have the same type ignoring cv-qualifiers; otherwise, it is the expression transform_sender(dom, transformed-sndr, env...).

However, the use of the phrase "have the same type ignoring cv-qualifiers" asks to compare the types without const or volatile qualifiers, but doesn't take into account differences in value category of the types of these expressions.

For example sndr might have type T&& and transformed-sndr might return a new prvalue of type T.

My interpretation of the current wording is that I should apply the test same_as<remove_cv_t<decltype(sndr)>, remove_cv_t<decltype(transformed-sndr)>>.

However, remove_cv_t does not remove reference-qualifiers from a type Sndr&& (which in the above example, is the type of sndr), and thus would compare as different to a transform-sndr type of Sndr.

I believe the intention is that this should instead use same_as<remove_cvref_t<decltype(sndr)>, remove_cvref_t<decltype(transformed-sndr)>>. For example, the implementation in NVIDIA's stdexec repository uses same_as<decay_t<T>, decay_t<U>> for this check.

The wording should be modified to use a phrase that removes both reference and cv-qualifiers when comparing types.

Proposed resolution:

This wording is relative to N5014.

  1. Modify 33.9.6 [exec.snd.transform] as indicated:

    namespace std::execution {
      template<class Domain, sender Sndr, queryable... Env>
        requires (sizeof...(Env) <= 1)
      constexpr sender decltype(auto) transform_sender(Domain dom, Sndr&& sndr, const Env&... env)
        noexcept(see below);
    }
    

    -1- Let transformed-sndr be the expression

    dom.transform_sender(std::forward<Sndr>(sndr), env...)
    

    if that expression is well-formed; otherwise,

    default_domain().transform_sender(std::forward<Sndr>(sndr), env...)
    

    Let final-sndr be the expression transformed-sndr if transformed-sndr and sndr have the same decayed type ignoring cv-qualifiers; otherwise, it is the expression transform_sender(dom, transformed-sndr, env...).