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.
transform_sender
comparing types ignoring cv-qualifiers doesn't take into account differences in value categorySection: 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 expressiondom.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 expressiontransformed-sndr
iftransformed-sndr
andsndr
have the same type ignoring cv-qualifiers; otherwise, it is the expressiontransform_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.
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.
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 expressiondom.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 expressiontransformed-sndr
iftransformed-sndr
andsndr
have the same decayed typeignoring cv-qualifiers; otherwise, it is the expressiontransform_sender(dom, transformed-sndr, env...)
.