std::ranges::unique_copy, std::ranges::unique_copy_result
| Defined in header <algorithm>
|
||
| Call signature |
||
template< std::input_iterator I, std::sentinel_for<I> S,
std::weakly_incrementable O, class Proj = std::identity,
std::indirect_equivalence_relation<std::projected<I, Proj>>
C = ranges::equal_to >
requires std::indirectly_copyable<I, O> &&
(std::forward_iterator<I> ||
(std::input_iterator<O> &&
std::same_as<std::iter_value_t<I>, std::iter_value_t<O>>) ||
std::indirectly_copyable_storable<I, O>)
constexpr ranges::unique_copy_result<I, O>
unique_copy( I first, S last, O d_first, C comp = {}, Proj proj = {} );
|
(1) | (since C++20) |
template< ranges::input_range R, std::weakly_incrementable O,
class Proj = std::identity,
std::indirect_equivalence_relation
<std::projected<ranges::iterator_t<R>, Proj>>
C = ranges::equal_to >
requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
(std::forward_iterator<ranges::iterator_t<R>> ||
(std::input_iterator<O> &&
std::same_as<ranges::range_value_t<R>, std::iter_value_t<O>>) ||
std::indirectly_copyable_storable<ranges::iterator_t<R>, O>)
constexpr ranges::unique_copy_result<ranges::borrowed_iterator_t<R>, O>
unique_copy( R&& r, O d_first, C comp = {}, Proj proj = {} );
|
(2) | (since C++20) |
template< /*execution-policy*/ Ep,
std::random_access_iterator I, std::sized_sentinel_for<I> S,
std::random_access_iterator O, std::sized_sentinel_for<O> OutS,
class Proj = std::identity,
std::indirect_equivalence_relation<std::projected<I, Proj>>
C = ranges::equal_to >
requires std::indirectly_copyable<I, O>
ranges::unique_copy_result<I, O>
unique_copy( Ep&& policy, I first, S last, O d_first, OutS d_last,
C comp = {}, Proj proj = {} );
|
(3) | (since C++26) |
template< /*execution-policy*/ Ep,
/*sized-random-access-range*/ R,
/*sized-random-access-range*/ OutR,
class Proj = std::identity,
std::indirect_equivalence_relation
<std::projected<ranges::iterator_t<R>, Proj>>
C = ranges::equal_to >
requires std::indirectly_copyable<ranges::iterator_t<R>,
ranges::iterator_t<OutR>>
ranges::unique_copy_result<ranges::borrowed_iterator_t<R>,
ranges::borrowed_iterator_t<OutR>>
unique_copy( Ep&& policy, R&& r, OutR&& d_r, C comp = {}, Proj proj = {});
|
(4) | (since C++26) |
| Helper types |
||
template< class I, class O >
using unique_copy_result = ranges::in_out_result<I, O>;
|
(5) | (since C++20) |
For the definition of /*execution-policy*/, see this page; for the definition of /*sized-random-access-range*/, see this page.
Copies elements from the source range [first, last) or r to the destination range. For each group of consecutive equivalent elements (projected by proj), only the first element is copied.
d_first.policy. If the destination range is exhausted before reaching the end of the source range, the remaining elements in the source range will not be copied.[d_first, d_last).d_r.If the source and destination ranges overlap, the behavior is undefined.
The function-like entities described on this page are algorithm function objects (informally known as niebloids), that is:
- Explicit template argument lists cannot be specified when calling any of them.
- None of them are visible to argument-dependent lookup.
- When any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.
Parameters
| first, last | - | the iterator-sentinel pair defining the source range |
| r | - | the source range |
| d_first | - | the beginning of the destination range |
| d_last | - | the sentinel of the destination range |
| d_r | - | the destination range |
| comp | - | the predicate to be applied to the (projected) elements |
| proj | - | the projection to be applied to the elements in the source range |
| policy | - | the execution policy to use |
Return value
A ranges::unique_copy_result object where:
- The data member in holds the past-the-end iterator of the source range.
proj), in holds an iterator to the first element of first such group instead.- The data member out holds an iterator past the last assigned element in the destination range, or an iterator to the beginning of the destination range if no element is assigned.
Complexity
Given N as ranges::distance(first, last) or ranges::distance(r):
comp, and at most twice as many applications of proj.comp, and at most twice as many applications of proj.Exceptions
- If the temporary memory resources required for parallelization are not available, std::bad_alloc is thrown.
- If an uncaught exception is thrown while accessing objects via an algorithm argument, the behavior is determined by the execution policy (for standard policies, std::terminate is invoked).
Possible implementation
See also the implementations in libstdc++ and MSVC STL (and third-party libraries: cmcstl2, NanoRange, and range-v3).
struct unique_copy_fn
{
template<std::input_iterator I, std::sentinel_for<I> S,
std::weakly_incrementable O, class Proj = std::identity,
std::indirect_equivalence_relation
<std::projected<I, Proj>> C = ranges::equal_to>
requires std::indirectly_copyable<I, O> &&
(std::forward_iterator<I> ||
(std::input_iterator<O> &&
std::same_as<std::iter_value_t<I>, std::iter_value_t<O>>) ||
std::indirectly_copyable_storable<I, O>)
constexpr ranges::unique_copy_result<I, O>
operator()(I first, S last, O result, C comp = {}, Proj proj = {}) const
{
if (!(first == last))
{
std::iter_value_t<I> value = *first;
*result = value;
++result;
while (!(++first == last))
{
auto&& value2 = *first;
if (!std::invoke(comp, std::invoke(proj, value2),
std::invoke(proj, value)))
{
value = std::forward<decltype(value2)>(value2);
*result = value;
++result;
}
}
}
return {std::move(first), std::move(result)};
}
template<ranges::input_range R,
std::weakly_incrementable O, class Proj = std::identity,
std::indirect_equivalence_relation
<std::projected<ranges::iterator_t<R>, Proj>> C = ranges::equal_to>
requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
(std::forward_iterator<ranges::iterator_t<R>> ||
(std::input_iterator<O> &&
std::same_as<ranges::range_value_t<R>, std::iter_value_t<O>>) ||
std::indirectly_copyable_storable<ranges::iterator_t<R>, O>)
constexpr ranges::unique_copy_result<ranges::borrowed_iterator_t<R>, O>
operator()(R&& r, O result, C comp = {}, Proj proj = {}) const
{
return (*this)(ranges::begin(r), ranges::end(r),
std::move(result), std::move(comp), std::move(proj));
}
template<ranges::forward_range R,
std::weakly_incrementable O, class Proj = std::identity,
std::indirect_equivalence_relation
<std::projected<ranges::iterator_t<R>, Proj>> C = ranges::equal_to>
requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
(std::forward_iterator<ranges::iterator_t<R>> ||
(std::input_iterator<O> &&
std::same_as<ranges::range_value_t<R>, std::iter_value_t<O>>) ||
std::indirectly_copyable_storable<ranges::iterator_t<R>, O>)
constexpr ranges::unique_copy_result<ranges::borrowed_iterator_t<R>, O>
operator()(R&& r, O result, C comp = {}, Proj proj = {}) const
{
return (*this)(ranges::begin(r),
ranges::next(ranges::begin(r), ranges::end(r)),
std::move(result), std::move(comp), std::move(proj));
}
};
inline constexpr unique_copy_fn unique_copy{};
|
Example
#include <algorithm>
#include <cmath>
#include <iostream>
#include <iterator>
#include <list>
#include <string>
#include <type_traits>
void print(const auto& rem, const auto& v)
{
using V = std::remove_cvref_t<decltype(v)>;
constexpr bool sep{std::is_same_v<typename V::value_type, int>};
std::cout << rem << std::showpos;
for (const auto& e : v)
std::cout << e << (sep ? " " : "");
std::cout << '\n';
}
int main()
{
std::string s1{"The string with many spaces!"};
print("s1: ", s1);
std::string s2;
std::ranges::unique_copy
(
s1.begin(), s1.end(), std::back_inserter(s2),
[](char c1, char c2) { return c1 == ' ' && c2 == ' '; }
);
print("s2: ", s2);
const auto v1 = {-1, +1, +2, -2, -3, +3, -3};
print("v1: ", v1);
std::list<int> v2;
std::ranges::unique_copy
(
v1, std::back_inserter(v2),
{}, // default comparator std::ranges::equal_to
[](int x) { return std::abs(x); } // projection
);
print("v2: ", v2);
}
Output:
s1: The string with many spaces!
s2: The string with many spaces!
v1: -1 +1 +2 -2 -3 +3 -3
v2: -1 +2 -3
