Skip to main content

std::ranges::copy_if() algorithm

// (1)
constexpr copy_if_result<I, O>
copy_if( I first, S last, O result, Pred pred, Proj proj = {} );

// (2)
constexpr copy_if_result<ranges::borrowed_iterator_t<R>, O>
copy_if( R&& r, O result, Pred pred, Proj proj = {} );

The type of arguments are generic and have following constraints:

  • I - std::input_iterator
  • S - std::sentinel_for<I>
  • O - std::weakly_incrementable
  • 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_copyable<I, O>
  • (2) - std::indirectly_copyable<ranges::iterator_t<R>, O>

With the helper types defined as follows:

template< class I, class O >
using copy_if_result = ranges::in_out_result<I, O>;

Copies the elements in the range, defined by [first; last), to another range beginning at result.

  • (1) Only copies the elements for which the predicate pred returns true. The relative order of the elements that are copied is preserved.

    Undefined Behaviour

    The behavior is undefined if result is within the range [first; last).

  • (2) Same as (1), but uses r as the source range, as if using ranges::begin(r) as first and ranges::end(r) as last.

The function-like entities described on this page are niebloids.

Parameters

first
last

The range of elements to copy.

r

The range of elements to copy.

result

The beginning of the destination range.

pred

Predicate to apply to the projected elements.

proj

Projection to apply to the elements.

Return value

A ranges::in_out_result containing an input iterator equal to last and an output iterator past the last element copied.

Complexity

Exactly last - first assignments.

Exactly last - first applications of the predicate and projection, between 0 and last - first assignments (assignment for every element for which predicate returns true).

Exceptions

(none)

Possible implementation

copy_if(1) and copy_if(2)
struct copy_if_fn
{
template<std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
requires std::indirectly_copyable<I, O>
constexpr ranges::copy_if_result<I, O>
operator()(I first, S last, O result, Pred pred, Proj proj = {}) const
{
for (; first != last; ++first)
if (std::invoke(pred, std::invoke(proj, *first)))
{
*result = *first;
++result;
}
return {std::move(first), std::move(result)};
}

template<ranges::input_range R, std::weakly_incrementable O,
class Proj = std::identity,
std::indirect_unary_predicate<
std::projected<ranges::iterator_t<R>, Proj>> Pred>
requires std::indirectly_copyable<ranges::iterator_t<R>, O>
constexpr ranges::copy_if_result<ranges::borrowed_iterator_t<R>, O>
operator()(R&& r, O result, Pred pred, Proj proj = {}) const
{
return (*this)(ranges::begin(r), ranges::end(r),
std::move(result),
std::ref(pred), std::ref(proj));
}
};

inline constexpr copy_if_fn copy_if;

Notes

In practice, implementations of ranges::copy_if avoid multiple assignments and use bulk copy functions such as std::memmove if the value type is TriviallyCopyable and the iterator types satisfy contiguous_iterator.

Examples

The following code uses ranges::copy_if to both copy the contents of one std::vector to another and to display the resulting std::vector:

Main.cpp
#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>

int main()
{
std::vector<int> source(10);
std::iota(source.begin(), source.end(), 0);

std::vector<int> destination;

std::ranges::copy_if(source.begin(), source.end(),
std::back_inserter(destination));
// or, alternatively,
// std::vector<int> destination(source.size());
// std::ranges::copy_if(source.begin(), source.end(), destination.begin());
// either way is equivalent to
// std::vector<int> destination = source;

std::cout << "destination contains: ";

std::ranges::copy_if(destination, std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';

std::cout << "odd numbers in destination are: ";

std::ranges::copy_if_if(destination, std::ostream_iterator<int>(std::cout, " "),
[](int x) { return (x % 2) == 1; });
std::cout << '\n';
}
Output
destination contains: 0 1 2 3 4 5 6 7 8 9
odd numbers in destination are: 1 3 5 7 9
This article originates from this CppReference page. It was likely altered for improvements or editors' preference. Click "Edit this page" to see all changes made to this document.
Hover to see the original license.

std::ranges::copy_if() algorithm

// (1)
constexpr copy_if_result<I, O>
copy_if( I first, S last, O result, Pred pred, Proj proj = {} );

// (2)
constexpr copy_if_result<ranges::borrowed_iterator_t<R>, O>
copy_if( R&& r, O result, Pred pred, Proj proj = {} );

The type of arguments are generic and have following constraints:

  • I - std::input_iterator
  • S - std::sentinel_for<I>
  • O - std::weakly_incrementable
  • 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_copyable<I, O>
  • (2) - std::indirectly_copyable<ranges::iterator_t<R>, O>

With the helper types defined as follows:

template< class I, class O >
using copy_if_result = ranges::in_out_result<I, O>;

Copies the elements in the range, defined by [first; last), to another range beginning at result.

  • (1) Only copies the elements for which the predicate pred returns true. The relative order of the elements that are copied is preserved.

    Undefined Behaviour

    The behavior is undefined if result is within the range [first; last).

  • (2) Same as (1), but uses r as the source range, as if using ranges::begin(r) as first and ranges::end(r) as last.

The function-like entities described on this page are niebloids.

Parameters

first
last

The range of elements to copy.

r

The range of elements to copy.

result

The beginning of the destination range.

pred

Predicate to apply to the projected elements.

proj

Projection to apply to the elements.

Return value

A ranges::in_out_result containing an input iterator equal to last and an output iterator past the last element copied.

Complexity

Exactly last - first assignments.

Exactly last - first applications of the predicate and projection, between 0 and last - first assignments (assignment for every element for which predicate returns true).

Exceptions

(none)

Possible implementation

copy_if(1) and copy_if(2)
struct copy_if_fn
{
template<std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
requires std::indirectly_copyable<I, O>
constexpr ranges::copy_if_result<I, O>
operator()(I first, S last, O result, Pred pred, Proj proj = {}) const
{
for (; first != last; ++first)
if (std::invoke(pred, std::invoke(proj, *first)))
{
*result = *first;
++result;
}
return {std::move(first), std::move(result)};
}

template<ranges::input_range R, std::weakly_incrementable O,
class Proj = std::identity,
std::indirect_unary_predicate<
std::projected<ranges::iterator_t<R>, Proj>> Pred>
requires std::indirectly_copyable<ranges::iterator_t<R>, O>
constexpr ranges::copy_if_result<ranges::borrowed_iterator_t<R>, O>
operator()(R&& r, O result, Pred pred, Proj proj = {}) const
{
return (*this)(ranges::begin(r), ranges::end(r),
std::move(result),
std::ref(pred), std::ref(proj));
}
};

inline constexpr copy_if_fn copy_if;

Notes

In practice, implementations of ranges::copy_if avoid multiple assignments and use bulk copy functions such as std::memmove if the value type is TriviallyCopyable and the iterator types satisfy contiguous_iterator.

Examples

The following code uses ranges::copy_if to both copy the contents of one std::vector to another and to display the resulting std::vector:

Main.cpp
#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>

int main()
{
std::vector<int> source(10);
std::iota(source.begin(), source.end(), 0);

std::vector<int> destination;

std::ranges::copy_if(source.begin(), source.end(),
std::back_inserter(destination));
// or, alternatively,
// std::vector<int> destination(source.size());
// std::ranges::copy_if(source.begin(), source.end(), destination.begin());
// either way is equivalent to
// std::vector<int> destination = source;

std::cout << "destination contains: ";

std::ranges::copy_if(destination, std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';

std::cout << "odd numbers in destination are: ";

std::ranges::copy_if_if(destination, std::ostream_iterator<int>(std::cout, " "),
[](int x) { return (x % 2) == 1; });
std::cout << '\n';
}
Output
destination contains: 0 1 2 3 4 5 6 7 8 9
odd numbers in destination are: 1 3 5 7 9
This article originates from this CppReference page. It was likely altered for improvements or editors' preference. Click "Edit this page" to see all changes made to this document.
Hover to see the original license.