ranges::unique_copy
's constraints for the case where result
is an
input_iterator
are not quite rightSection: 26.7.9 [alg.unique] Status: New Submitter: Hewill Kang Opened: 2024-05-14 Last modified: 2024-06-24
Priority: 3
View all other issues in [alg.unique].
View all issues with New status.
Discussion:
When r
is only an input_range
and result
is also an
input_iterator
, ranges::unique_copy
writes the elements of r
into result
and reads the value of result
in the next iteration.
value_type
of r
and the value_type
of result
are the same, which seems too loose because
the value_type
is not particularly useful in the ranges world compared to the
reference
, which is also reflected in the fact that the implementation applies the
compare function on both dereferenced values (demo):
#include <algorithm>
#include <iostream>
#include <ranges>
#include <vector>
int main() {
auto r = std::views::istream<bool>(std::cin);
std::vector<bool> v(10);
auto proj = [](std::same_as<bool> auto b) { return b; }; // ban vector<bool>::reference
std::ranges::unique_copy(r, v.begin(), {}, proj); // hard error in libstdc++, libc++ and MSVC-STL
}
[2024-06-24; Reflector poll]
Set priority to 3 after reflector poll.
Proposed resolution:
This wording is relative to N4981.
Modify 26.4 [algorithm.syn], header <algorithm>
synopsis, as indicated:
#include <initializer_list> // see [initializer.list.syn] namespace std { […] namespace ranges { template<class I, class O> using unique_copy_result = in_out_result<I, O>; template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity, indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to> requires indirectly_copyable<I, O> && (forward_iterator<I> || (input_iterator<O> &&same_as<iter_value_t<I>, iter_value_t<O>>indirect_equivalence_relation<C, projected<I, Proj>, projected<O, Proj>>) || indirectly_copyable_storable<I, O>) constexpr unique_copy_result<I, O> unique_copy(I first, S last, O result, C comp = {}, Proj proj = {}); template<input_range R, weakly_incrementable O, class Proj = identity, indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to> requires indirectly_copyable<iterator_t<R>, O> && (forward_iterator<iterator_t<R>> || (input_iterator<O> &&same_as<range_value_t<R>, iter_value_t<O>>indirect_equivalence_relation<C, projected<iterator_t<R>, Proj>, projected<O, Proj>>) || indirectly_copyable_storable<iterator_t<R>, O>) constexpr unique_copy_result<borrowed_iterator_t<R>, O> unique_copy(R&& r, O result, C comp = {}, Proj proj = {}); } […] }
Modify 26.7.9 [alg.unique] as indicated:
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity, indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to> requires indirectly_copyable<I, O> && (forward_iterator<I> || (input_iterator<O> &&same_as<iter_value_t<I>, iter_value_t<O>>indirect_equivalence_relation<C, projected<I, Proj>, projected<O, Proj>>) || indirectly_copyable_storable<I, O>) constexpr ranges::unique_copy_result<I, O> ranges::unique_copy(I first, S last, O result, C comp = {}, Proj proj = {}); template<input_range R, weakly_incrementable O, class Proj = identity, indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to> requires indirectly_copyable<iterator_t<R>, O> && (forward_iterator<iterator_t<R>> || (input_iterator<O> &&same_as<range_value_t<R>, iter_value_t<O>>indirect_equivalence_relation<C, projected<iterator_t<R>, Proj>, projected<O, Proj>>) || indirectly_copyable_storable<iterator_t<R>, O>) constexpr ranges::unique_copy_result<borrowed_iterator_t<R>, O> ranges::unique_copy(R&& r, O result, C comp = {}, Proj proj = {});-6- Let
pred
beequal_to{}
for the overloads in namespacestd
with no parameterpred
, […]