There are several instances where we pass a function, f, to an algorithm and then define F as the decayed type of f and then require that F satisfies movable-value.
However, I think that we should instead be defining F as decltype((f)) rather than the decayed type of f.
Consider the case where I have a lambda with captures that are move-only and I pass this to an algorithm as an const-lvalue. The decayed type of f is the cvref-unqualified type which satisfies movable-value because the lambda type itself is move_constructible, yet the implementation will want to decay-copy the argument, which will fail because it cannot initialize a copy of the lambda from the argument passed.
This same wording occurs in the following sections:
[exec.then]
[exec.let]
[exec.bulk]
e.g. in [exec.then]
... For subexpressions sndr and f, let Sndr be decltype((sndr)) and let F be the decayed type of f. If Sndr does not satisfy sender, or F does not satisfy movable-value, then-cpo(sndr, f) is ill-formed.
There are several instances where we pass a function,
f
, to an algorithm and then defineF
as the decayed type off
and then require thatF
satisfiesmovable-value
.However, I think that we should instead be defining
F
asdecltype((f))
rather than the decayed type off
.Consider the case where I have a lambda with captures that are move-only and I pass this to an algorithm as an const-lvalue. The decayed type of
f
is the cvref-unqualified type which satisfiesmovable-value
because the lambda type itself ismove_constructible
, yet the implementation will want to decay-copy the argument, which will fail because it cannot initialize a copy of the lambda from the argument passed.This same wording occurs in the following sections:
[exec.then]
[exec.let]
[exec.bulk]
e.g. in
[exec.then]