1. Changelog
- 
     R0: - 
       Initial revision. 
 
- 
       
2. Motivation and solution
The "classic STL" provides the following sets of related algorithms:
- 
     is_sorted_until is_sorted is_sorted_until == end () 
- 
     is_heap_until is_heap is_heap_until == end () 
- 
     adjacent_find adjacent_find == end () 
- 
     mismatch equal mismatch == { end (), end ()} 
- 
     search contains_subrange search != end () 
And these, too:
- 
     unique 
The missing algorithm is what would fill in the blank in the following invariant assertions:
std :: set < K > s = { ... }; std :: multiset < K > ms = { ... }; std :: map < K , V > m = { ... }; std :: multimap < K , V > mm = { ... }; std :: unordered_set < K > us = { ... }; std :: unordered_map < K , V > um = { ... }; template < class M , class P = M :: value_type > auto ValueEq ( const M & m ) { return [ eq = m . key_eq ()]( const P & a , const P & b ) { return eq ( a . first , b . first ); }; } assert ( std :: is_sorted ( s . begin (), s . end (), s . value_comp ())); assert ( std :: is_sorted ( ms . begin (), ms . end (), ms . value_comp ())); assert ( std :: is_sorted ( m . begin (), m . end (), m . value_comp ())); assert ( std :: is_sorted ( mm . begin (), mm . end (), mm . value_comp ())); assert ( std :: is______ed ( s . begin (), s . end (), std :: not_fn ( s . value_comp ()))); assert ( std :: is______ed ( m . begin (), m . end (), std :: not_fn ( m . value_comp ()))); assert ( std :: is______ed ( us . begin (), us . end (), us . key_eq ())); assert ( std :: is______ed ( um . begin (), um . end (), ValueEq ( um ))); 
We propose that this algorithm should exist, and should be spelled 
2.1. Prior art in other languages
The C++ STL verb 
The Swift language provides a transformation named 
let animals = [ "dog" , "pig" , "cat" , "ox" , "dog" , "cat" ] let u = Array ( animals . uniqued ()) // 'u' is now ["dog", "pig", "cat", "ox"] 
2.2. Should we require pred 
   Currently, 
For example, the author of 
container_type c ; key_compare compare ; std :: sort ( c . begin (), c . end (), compare ); c . erase ( std :: unique ( c . begin (), c . end (), std :: not_fn ( compare )), c . end ()); // UB assert ( std :: is_sorted ( c . begin (), c . end (), compare )); assert ( std :: adjacent_find ( c . begin (), c . end (), std :: not_fn ( compare )) == c . end ()); // OK 
Both before and after this proposal, the line marked "UB" has undefined behavior (although
it will generally work in practice). We don’t propose to change the precondition
of 
After this proposal, the following shorter line will be equivalent to the line marked "OK":
assert ( std :: is_uniqued ( c . begin (), c . end (), std :: not_fn ( compare ))); // OK 
That is, the new algorithm 
3. Implementation experience
Arthur has implemented 
4. Proposed wording relative to C++23
Add a new section after [alg.adjacent.find].
Note: This wording is copied straight from [is.sorted],
with these mechanical replacements: 
4.1. is_uniqued 
   
   template < class ForwardIterator > constexpr bool is_uniqued ( ForwardIterator first , ForwardIterator last ); Effects: Equivalent to:
return adjacent_find ( first , last ) == last ; template < class ExecutionPolicy , class ForwardIterator > bool is_uniqued ( ExecutionPolicy && exec , ForwardIterator first , ForwardIterator last ); Effects: Equivalent to:
return adjacent_find ( std :: forward < ExecutionPolicy > ( exec ), first , last ) == last ; template < class ForwardIterator , class BinaryPredicate > constexpr bool is_uniqued ( ForwardIterator first , ForwardIterator last , BinaryPredicate pred ); Effects: Equivalent to:
return adjacent_find ( first , last , pred ) == last ; template < class ExecutionPolicy , class ForwardIterator , class BinaryPredicate > bool is_uniqued ( ExecutionPolicy && exec , ForwardIterator first , ForwardIterator last , BinaryPredicate pred ); Effects: Equivalent to:
return adjacent_find ( std :: forward < ExecutionPolicy > ( exec ), first , last , pred ) == last ; template < forward_iterator I , sentinel_for < I > S , class Proj = identity , indirect_binary_predicate < projected < I , Proj > , projected < I , Proj >> Pred = ranges :: equal_to > constexpr bool ranges :: is_uniqued ( I first , S last , Pred pred = {}, Proj proj = {}); template < forward_range R , class Proj = identity , indirect_binary_predicate < projected < iterator_t < R > , Proj > , projected < iterator_t < R > , Proj >> Pred = ranges :: equal_to > constexpr bool ranges :: is_uniqued ( R && r , Pred pred = {}, Proj proj = {}); Effects: Equivalent to:
return ranges :: adjacent_find ( first , last , pred , proj ) == last ;