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.
ranges::for_each(_n)
should be less constrainedSection: 26.6.5 [alg.foreach] Status: New Submitter: Jiang An Opened: 2025-04-08 Last modified: 2025-04-13
Priority: Not Prioritized
View other active issues in [alg.foreach].
View all other issues in [alg.foreach].
View all issues with New status.
Discussion:
Currently, ranges::for_each(_n)
are constrained with indirectly_unary_invocable
,
which doesn't meet the actual use of the range elements. These algorithms are only
expected to invoke the callable object with the possibly projected elements, and not
to use any element as the value type. Moreover, indirectly_unary_invocable
requires
the callable object to be copy constructible, which might be undesired because the
corresponding std::for_each(_n)
only require move constructibilty.
ranges::for_each
introduced
by P2609R3. P2609R3 looks like a reasonable fix as long as the affected
algorithms potentially use the intermediate element values copied as
std::iter_value_t<I>
. However, when the algorithm is not expected to or
even required not to do this, P2609R3 can bring unexpected impacts. It seems that
constraints around iter_value_t
should be avoided for such an algorithm.
Proposed resolution:
This wording is relative to N5008.
Modify 26.4 [algorithm.syn], header <algorithm>
synopsis, as indicated:
[…] namespace ranges { template<class I, class F> using for_each_result = in_fun_result<I, F>; template<input_iterator I, sentinel_for<I> S, class Proj = identity,indirectly_unary_invocable<projected<I, Proj>>move_constructible Fun> requires invocable<Fun&, iter_reference_t<projected<I, Proj>>> constexpr for_each_result<I, Fun> for_each(I first, S last, Fun f, Proj proj = {}); template<input_range R, class Proj = identity,indirectly_unary_invocable<projected<iterator_t<R>, Proj>>move_constructible Fun> requires invocable<Fun&, iter_reference_t<projected<iterator_t<R>, Proj>>> constexpr for_each_result<borrowed_iterator_t<R>, Fun> for_each(R&& r, Fun f, Proj proj = {}); } […] namespace ranges { template<class I, class F> using for_each_n_result = in_fun_result<I, F>; template<input_iterator I, class Proj = identity,indirectly_unary_invocable<projected<I, Proj>>move_constructible Fun> requires invocable<Fun&, iter_reference_t<projected<I, Proj>>> constexpr for_each_n_result<I, Fun> for_each_n(I first, iter_difference_t<I> n, Fun f, Proj proj = {}); } […]
Modify 26.6.5 [alg.foreach] as indicated:
template<input_iterator I, sentinel_for<I> S, class Proj = identity,indirectly_unary_invocable<projected<I, Proj>>move_constructible Fun> requires invocable<Fun&, iter_reference_t<projected<I, Proj>>> constexpr ranges::for_each_result<I, Fun> ranges::for_each(I first, S last, Fun f, Proj proj = {}); template<input_range R, class Proj = identity,indirectly_unary_invocable<projected<iterator_t<R>, Proj>>move_constructible Fun> requires invocable<Fun&, iter_reference_t<projected<iterator_t<R>, Proj>>> constexpr ranges::for_each_result<borrowed_iterator_t<R>, Fun> ranges::for_each(R&& r, Fun f, Proj proj = {});[…]
-15- [Note 6: The overloads in namespaceranges
requireFun
to modelcopy_constructible
. — end note][…]
template<input_iterator I, class Proj = identity,indirectly_unary_invocable<projected<I, Proj>>move_constructible Fun> requires invocable<Fun&, iter_reference_t<projected<I, Proj>>> constexpr ranges::for_each_n_result<I, Fun> ranges::for_each_n(I first, iter_difference_t<I> n, Fun f, Proj proj = {});[…]
-30- [Note 11: The overload in namespaceranges
requiresFun
to modelcopy_constructible
. — end note]