std::ranges::replace_if() algorithm
- od C++20
- Simplified
- Detailed
// (1)
constexpr I
replace_if( I first, S last, Pred pred, const T& new_value, Proj proj = {} );
// (2)
constexpr ranges::borrowed_iterator_t<R>
replace_if( R&& r, Pred pred, const T& new_value, Proj proj = {} );
The type of arguments are generic and have the following constraints:
I
-std::input_iterator
S
-std::sentinel_for<I>
R
-std::ranges::input_range
T
- (none)Proj
- (none)Pred
:- (1) -
std::indirect_unary_predicate<std::projected<I, Proj>>
- (2) -
std::indirect_unary_predicate< std::projected<ranges::iterator_t<R>, Proj>>
The Proj
template argument has a default type of std::identity
for all overloads.
Additionally, each overload has the following constraints:
- (1) -
std::indirectly_writable<I, const T&>
- (2) -
std::indirectly_writable<ranges::iterator_t<R>, const T&>
(The std::
namespace was ommitted here for readability)
// (1)
template<
std::input_iterator I,
std::sentinel_for<I> S,
class T,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred
>
requires std::indirectly_writable<I, const T&>
constexpr I
replace_if( I first, S last, Pred pred, const T& new_value, Proj proj = {} );
// (2)
template<
ranges::input_range R,
class T, class Proj = std::identity,
std::indirect_unary_predicate< std::projected<ranges::iterator_t<R>, Proj>> Pred
>
requires std::indirectly_writable<ranges::iterator_t<R>, const T&>
constexpr ranges::borrowed_iterator_t<R>
replace_if( R&& r, Pred pred, const T& new_value, Proj proj = {} );
-
(1) Replaces all elements for which the predicate
pred
evaluates totrue
, where evaluating expression isstd::invoke(pred, std::invoke(proj, *i))
. -
(2) Same as (1), but uses
r
as the source range, as if usingranges::begin(r)
asfirst
andranges::end(r)
aslast
.
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be replaced appear in the beginning of the range.
Relative order of the elements that remain is preserved and the physical size of the container is unchanged.
Iterators pointing to an element between the new logical end and the physical end of the range are still dereferenceable, but the elements themselves have unspecified values (as per MoveAssignable post-condition). (od C++11)
The function-like entities described on this page are niebloids.
Parameters
first last | The range of elements to process. |
r | The range of elements to process. |
new_value | The value to use as a replacement. |
proj | Projection to apply to the elements. |
pred | Unary predicate which returns |
Return value
An iterator equal to last
.
Complexity
Exactly ranges::distance(first, last)
applications of the corresponding predicate pred
and any projection proj
.
Exceptions
(none)
Possible implementation
replace_if(1)
struct replace_if_fn
{
template<std::input_iterator I, std::sentinel_for<I> S, class T,
class Proj = std::identity, std::indirect_unary_predicate<
std::projected<I, Proj>> Pred>
requires std::indirectly_writable<I, const T&>
constexpr I
operator()(I first, S last, Pred pred, const T& new_value, Proj proj = {}) const
{
for (; first != last; ++first)
if (!!std::invoke(pred, std::invoke(proj, *first)))
*first = new_value;
return std::move(first);
}
template<ranges::input_range R, class T, class Proj = std::identity,
std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred>
requires std::indirectly_writable<ranges::iterator_t<R>, const T&>
constexpr ranges::borrowed_iterator_t<R>
operator()(R&& r, Pred pred, const T& new_value, Proj proj = {}) const
{
return (*this)(ranges::begin(r), ranges::end(r), std::move(pred),
new_value, std::move(proj));
}
};
inline constexpr replace_if_fn replace_if {};
Notes
Because the algorithm takes old_value
and new_value
by reference, it may have unexpected behavior if either is a reference to an element of the range [first
; last
).
Examples
#include <algorithm>
#include <array>
#include <iostream>
int main()
{
auto print = [](const auto& v)
{
for (const auto& e : v)
std::cout << e << ' ';
std::cout << '\n';
};
std::array p {1, 6, 1, 6, 1, 6};
print(p);
std::ranges::replace(p, 6, 9);
print(p);
std::array q {1, 2, 3, 6, 7, 8, 4, 5};
print(q);
std::ranges::replace_if(q, [](int x) { return 5 < x; }, 5);
print(q);
}
1 6 1 6 1 6
1 9 1 9 1 9
1 2 3 6 7 8 4 5
1 2 3 5 5 5 4 5
Hover to see the original license.