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.
std::ranges::fold_left_first_with_iter
should be more ADL-proofSection: 26.6.18 [alg.fold] Status: New Submitter: Jiang An Opened: 2023-08-10 Last modified: 2023-11-03
Priority: 3
View other active issues in [alg.fold].
View all other issues in [alg.fold].
View all issues with New status.
Discussion:
The following program is currently ill-formed, because 26.6.18 [alg.fold]/10 requires evaluating
*init
, where init
is an object of an optional
specialization, which triggers
ADL and finds unwanted overloads.
#include <algorithm> #include <optional> namespace myns { struct Foo {}; void operator*(std::optional<Foo>&); void operator*(const std::optional<Foo>&); } int main() { myns::Foo x[1]{}; std::ranges::fold_left_first_with_iter(x, []<class T>(T lhs, T) { return lhs; }); }
I think only the member operator*
overload is intendedly used.
[2023-11-03; Reflector poll]
Many votes for NAD.
"Yuck, can we just use .value()
instead?"
"The example is not good motivation, but we should ADL-proof to avoid
attempting to complete incomplete associated classes."
Proposed resolution:
This wording is relative to N4950.
Modify 26.6.18 [alg.fold] as indicated:
template<input_iterator I, sentinel_for<I> S, indirectly-binary-left-foldable<iter_value_t<I>, I> F> requires constructible_from<iter_value_t<I>, iter_reference_t<I>> constexpr see below ranges::fold_left_first_with_iter(I first, S last, F f); template<input_range R, indirectly-binary-left-foldable<range_value_t<R>, iterator_t<R>> F> requires constructible_from<range_value_t<R>, range_reference_t<R>> constexpr see below ranges::fold_left_first_with_iter(R&& r, F f);-9- Let
U
bedecltype(ranges::fold_left(std::move(first), last, iter_value_t<I>(*first), f))-10- Effects: Equivalent to:
if (first == last) return {std::move(first), optional<U>()}; optional<U> init(in_place, *first); for (++first; first != last; ++first)*initinit.operator*() = invoke(f, std::move(*initinit.operator*()), *first); return {std::move(first), std::move(init)};