std::replac...:replace_if(3)

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

πŸ’… std::replace, std::replace_if β€” C++ Standard Libary (section 3) πŸ’…

okay so bestie, welcome to page std::replac...:replace_if(3) straight out of the C++ Standard Libary manual. Yes, β€œLibary” with one b β€” that’s the exact manual name and we are not fixing it, no cap. This is the group-chat rundown for std::replace and std::replace_if, and every single overload is coming with us. πŸ’–


✨ NAME ✨

std::replace,std::replace_if β€” std::replace,std::replace_if

literally the name is the name, periodt. πŸŽ€

🌸 Synopsis 🌸

Defined in header <algorithm>

the replace girlies

template< class ForwardIt, class T >
constexpr void replace( ForwardIt first, ForwardIt last,
                        const T& old_value, const T& new_value );

constexpr since C++20; until C++26.

template< class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type >
constexpr void replace( ForwardIt first, ForwardIt last,
                        const T& old_value, const T& new_value );

since C++26.

template< class ExecutionPolicy, class ForwardIt, class T >
void replace( ExecutionPolicy&& policy,
              ForwardIt first, ForwardIt last,
              const T& old_value, const T& new_value );

since C++17; until C++26.

template< class ExecutionPolicy, class ForwardIt,
          class T = typename std::iterator_traits<ForwardIt>::value_type >
void replace( ExecutionPolicy&& policy,
              ForwardIt first, ForwardIt last,
              const T& old_value, const T& new_value );

since C++26.

the numbered replace_if overloads

(1)

template< class ForwardIt, class UnaryPred, class T >
constexpr void replace_if( ForwardIt first, ForwardIt last,
                           UnaryPred p, const T& new_value );

constexpr since C++20; until C++26.

(2)

template< class ForwardIt, class UnaryPred,
          class T = typename std::iterator_traits<ForwardIt>::value_type >
constexpr void replace_if( ForwardIt first, ForwardIt last,
                           UnaryPred p, const T& new_value );

since C++26.

(3)

template< class ExecutionPolicy, class ForwardIt, class UnaryPred, class T >
void replace_if( ExecutionPolicy&& policy,
                 ForwardIt first, ForwardIt last,
                 UnaryPred p, const T& new_value );

since C++17; until C++26.

(4)

template< class ExecutionPolicy, class ForwardIt, class UnaryPred,
          class T = typename std::iterator_traits<ForwardIt>::value_type >
void replace_if( ExecutionPolicy&& policy,
                 ForwardIt first, ForwardIt last,
                 UnaryPred p, const T& new_value );

since C++26.

what it do, bestie

Replaces all elements in the range [first, last) with new_value if they satisfy specific criteria. πŸ’…

  1. Replaces all elements that are equal to old_value (using operator==).
  2. Replaces 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

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> is true.

since C++20

If *first = new_value is invalid (until C++20), or new_value is not writable to first (since C++20), the program is ill-formed. Like, not β€œoops,” actually ill-formed. 😭

πŸ¦‹ Parameters πŸ¦‹

  • first, last β€” the range of elements to process.
  • old_value β€” the value of elements to replace.
  • policy β€” the execution policy to use. See execution policy for details.
  • p β€” unary predicate which returns true if the element value should be replaced. The expression p(v) must be convertible to bool for every argument v of type (possibly const) VT, where VT is the value type of ForwardIt, regardless of value category, and must not modify v. Thus, a parameter type of VT& is not allowed, nor is VT unless for VT a move is equivalent to a copy (since C++11).
  • new_value β€” the value to use as replacement.

🌈 Type requirements 🌈

  • ForwardIt must meet the requirements of LegacyForwardIterator.
  • UnaryPred must meet the requirements of Predicate.

πŸŽ€ Return value πŸŽ€

(none)

that’s it. no sneaky return, bestie. 🫢

⭐ Complexity ⭐

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

  • 1,2) Exactly \(\scriptsize N\)N comparisons using operator==.
  • 3,4) Exactly \(\scriptsize N\)N applications of the predicate p.

πŸ”₯ 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.

πŸ’œ Notes πŸ’œ

Because the algorithm takes old_value and new_value by reference, it can have unexpected behavior if either is a reference to an element of the range [first, last).

that’s the β€œwait, what?” corner, bestie. read it twice. πŸ‘€

Feature-test macro:

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

🧚 Possible implementation 🧚

replace

template<class ForwardIt,
         class T = typename std::iterator_traits<ForwardIt>::value_type>
void replace(ForwardIt first, ForwardIt last,
             const T& old_value, const T& new_value)
{
    for (; first != last; ++first)
        if (*first == old_value)
            *first = new_value;
}

replace_if

template<class ForwardIt, class UnaryPred,
         class T = typename std::iterator_traits<ForwardIt>::value_type>
void replace_if(ForwardIt first, ForwardIt last,
                UnaryPred p, const T& new_value)
{
    for (; first != last; ++first)
        if (p(*first))
            *first = new_value;
}

🌸 Example 🌸

the page says // Run this code, so here’s the code, bestie:

#include <algorithm>
#include <array>
#include <complex>
#include <functional>
#include <iostream>

void println(const auto& seq)
{
    for (const auto& e : seq)
        std::cout << e << ' ';
    std::cout << '\n';
}

int main()
{
    std::array<int, 10> s{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};

    // Replace all occurrences of 8 with 88.
    std::replace(s.begin(), s.end(), 8, 88);
    println(s);

    // Replace all values less than 5 with 55.
    std::replace_if(s.begin(), s.end(),
                    std::bind(std::less<int>(), std::placeholders::_1, 5), 55);
    println(s);

    std::array<std::complex<double>, 2> nums{{{1, 3}, {1, 3}}};
    #ifdef __cpp_lib_algorithm_default_value_type
        std::replace(nums.begin(), nums.end(), {1, 3}, {4, 2});
    #else
        std::replace(nums.begin(), nums.end(), std::complex<double>{1, 3},
                                               std::complex<double>{4, 2});
    #endif
    println(nums);
}

πŸ“ Output πŸ“

5 7 4 2 88 6 1 9 0 3
5 7 55 55 88 6 55 9 55 55
(4,2), (4,2)

🌟 Defect reports 🌟

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

  • DR LWG 283, applied to C++98. Behavior as published: T was required to be CopyAssignable (and EqualityComparable for replace), but the value type of ForwardIt is not always T and T is not always writable to ForwardIt. Correct behavior: required *first = new_value to be valid instead.

πŸ‘‘ See also πŸ‘‘

  • replace_copy, replace_copy_if β€” copies a range, replacing elements satisfying specific criteria with another value (function template).
  • ranges::replace, ranges::replace_if (C++20) β€” replaces all values satisfying specific criteria with another value (niebloid) (C++20).

that’s the whole page, bestie πŸ«ΆπŸ’– β€” sourced from http://cppreference.com, version/date 2024.06.10, and the page label is std::replac...:replace_if(3). mwah πŸ’…βœ¨

πŸ“¦ where this page comes from