std::remove...ove_copy_if(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– NAME πŸ’–

okay bestie, this is the std::remove...ove_copy_if(3) page from the C++ Standard Libary manual (yes, the header really spells it like that 😭). We're talking about std::remove_copy and std::remove_copy_if β€” the algorithm girlies that copy a range to a new spot while skipping the elements that match your criteria. periodt ✨


πŸ¦‹ Synopsis πŸ¦‹

Defined in header <algorithm>:

template< class InputIt, class OutputIt,
          class T >
OutputIt remove_copy( InputIt first, InputIt last,
                      OutputIt d_first,
                      const T& value );

(1) Β· (constexpr since C++20) Β· (until C++26)

template< class InputIt, class OutputIt,
          class T = typename std::iterator_traits<InputIt>::value_type >
constexpr OutputIt remove_copy( InputIt first, InputIt last,
                                OutputIt d_first, const T& value );

(since C++26)

template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2, class T >
ForwardIt2 remove_copy( ExecutionPolicy&& policy,
                        ForwardIt1 first, ForwardIt1 last,
                        ForwardIt2 d_first, const T& value );

(2) Β· (since C++17) Β· (until C++26)

template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2,
          class T = typename std::iterator_traits<ForwardIt1>::value_type >
ForwardIt2 remove_copy( ExecutionPolicy&& policy,
                        ForwardIt1 first, ForwardIt1 last,
                        ForwardIt2 d_first, const T& value );

(since C++26)

template< class InputIt, class OutputIt,
          class UnaryPred >
OutputIt remove_copy_if( InputIt first, InputIt last,
                         OutputIt d_first,
                         UnaryPred p );

(3) Β· (constexpr since C++20)

template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2, class UnaryPred >
ForwardIt2 remove_copy_if( ExecutionPolicy&& policy,
                           ForwardIt1 first, ForwardIt1 last,
                           ForwardIt2 d_first, UnaryPred p );

(4) Β· (since C++17)

So what's the vibe? It copies elements from the range [first, last) to another range beginning at d_first, omitting the elements that satisfy specific criteria. iconic behavior, honestly πŸ’…

  • (1) β€” ignores all elements that are equal to value (using operator==).
  • (3) β€” ignores all elements for which predicate p returns true.
  • (2,4) β€” same as (1,3), but executed according to policy. These overloads participate in overload resolution only if std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> is true (until C++20), or std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> is true (since C++20).

If *d_first = *first is invalid (until C++20), or *first is not writable to d_first (since C++20), the program is ill-formed. no cap, that's strict.

If source and destination ranges overlap, the behavior is undefined. bestie do not overlap these ranges, I'm begging 😭

🌸 Parameters 🌸

  • first, last β€” the range of elements to copy.
  • d_first β€” the beginning of the destination range.
  • value β€” the value of the elements not to copy.
  • policy β€” the execution policy to use. See execution policy for details.

πŸŽ€ Type requirements πŸŽ€

  • InputIt must meet the requirements of LegacyInputIterator.
  • OutputIt must meet the requirements of LegacyOutputIterator.
  • ForwardIt1, ForwardIt2 must meet the requirements of LegacyForwardIterator.
  • UnaryPred must meet the requirements of Predicate.

πŸ’« Return value πŸ’«

Iterator to the element past the last element copied. literally the spot right after the copied stuff 🫢


πŸ”₯ Complexity πŸ”₯

Given N as std::distance(first, last):

  • (1,2) β€” exactly N comparisons with value using operator==.
  • (3,4) β€” exactly N applications of the predicate p.

For the overloads with an ExecutionPolicy, there may be a performance cost if ForwardIt1's value_type is not MoveConstructible. noted, bestie ✨


πŸ’€ Exceptions πŸ’€

The overloads with a template parameter named ExecutionPolicy report errors as follows:

  • If execution of a function invoked as part of the algorithm throws an exception and ExecutionPolicy is one of the standard policies, std::terminate is called. For any other ExecutionPolicy, the behavior is implementation-defined.
  • If the algorithm fails to allocate memory, std::bad_alloc is thrown.

🧚 Possible implementation 🧚

remove_copy (1)

template<class InputIt, class OutputIt,
         class T = typename std::iterator_traits<InputIt>::value_type>
constexpr OutputIt remove_copy(InputIt first, InputIt last,
                               OutputIt d_first, const T& value)
{
    for (; first != last; ++first)
        if (!(*first == value))
            *d_first++ = *first;
    return d_first;
}

remove_copy_if (3)

template<class InputIt, class OutputIt, class UnaryPred>
constexpr OutputIt remove_copy_if(InputIt first, InputIt last,
                                  OutputIt d_first, UnaryPred p)
{
    for (; first != last; ++first)
        if (!p(*first))
            *d_first++ = *first;
    return d_first;
}

⭐ Notes ⭐

Feature-test macro check, because of course:

  • __cpp_lib_algorithm_default_value_type β€” value 202403, standard (C++26), feature: List-initialization for algorithms (1,2).

πŸ“ Example πŸ“

#include <algorithm>
#include <complex>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

int main()
{
    // Erase the hash characters '#' on the fly.
    std::string str = "#Return #Value #Optimization";
    std::cout << "before: " << std::quoted(str) << '\n';

    std::cout << "after:  \"";
    std::remove_copy(str.begin(), str.end(),
                     std::ostream_iterator<char>(std::cout), '#');
    std::cout << "\"\n";

    // Erase {1, 3} value on the fly.
    std::vector<std::complex<double>> nums{{2, 2}, {1, 3}, {4, 8}, {1, 3}};
    std::remove_copy(nums.begin(), nums.end(),
                     std::ostream_iterator<std::complex<double>>(std::cout),
#ifdef __cpp_lib_algorithm_default_value_type
                     {1, 3}); // T gets deduced
#else
                     std::complex<double>{1, 3});
#endif
}

Output:

before: "#Return #Value #Optimization"
after:  "Return Value Optimization"
(2,2)(4,8)

πŸ’œ Defect reports πŸ’œ

The following behavior-changing defect reports were applied retroactively to previously published C++ standards:

  • LWG 779 β€” applied to C++98. Behavior as published: T was required to be EqualityComparable, but the value type of ForwardIt is not always T. Correct behavior: required *d_first = *first to be valid instead.

🌈 See also 🌈

  • remove β€” removes elements satisfying specific criteria (function template).
  • remove_if β€” removes elements satisfying specific criteria (function template).
  • copy β€” copies a range of elements to a new location (function template).
  • copy_if β€” copies a range of elements to a new location (C++11) (function template).
  • partition_copy β€” copies a range dividing the elements into two groups (C++11) (function template).
  • ranges::remove_copy β€” copies a range of elements omitting those that satisfy specific criteria (C++20) (niebloid).
  • ranges::remove_copy_if β€” copies a range of elements omitting those that satisfy specific criteria (C++20) (niebloid).

πŸ’Œ source: http://cppreference.com Β· version/date: 2024.06.10 Β· page: std::remove...ove_copy_if(3) β€” that's the whole page, bestie. now go copy some ranges, slay πŸ’…βœ¨

πŸ“¦ where this page comes from