Difference between revisions of "cpp/algorithm/replace copy"
m (→See also: + `std::replace`) |
m (FTM.) |
||
(12 intermediate revisions by 3 users not shown) | |||
Line 2: | Line 2: | ||
{{cpp/algorithm/navbar}} | {{cpp/algorithm/navbar}} | ||
{{dcl begin}} | {{dcl begin}} | ||
− | {{dcl header | algorithm}} | + | {{dcl header|algorithm}} |
− | {{ | + | <!-- P2248R8 does NOT update replace_copy --> |
+ | {{dcla|num=1|constexpr=c++20| | ||
template< class InputIt, class OutputIt, class T > | template< class InputIt, class OutputIt, class T > | ||
OutputIt replace_copy( InputIt first, InputIt last, OutputIt d_first, | OutputIt replace_copy( InputIt first, InputIt last, OutputIt d_first, | ||
const T& old_value, const T& new_value ); | const T& old_value, const T& new_value ); | ||
− | |||
− | |||
− | |||
− | |||
}} | }} | ||
− | {{dcl | since=c++17 | | + | {{dcl|num=2|since=c++17| |
− | template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T > | + | template< class ExecutionPolicy, |
− | ForwardIt2 replace_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last, | + | class ForwardIt1, class ForwardIt2, class T > |
− | + | ForwardIt2 replace_copy | |
+ | ( ExecutionPolicy&& policy, | ||
+ | ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first, | ||
+ | const T& old_value, const T& new_value ); | ||
+ | }} | ||
+ | {{dcl rev begin|num=3}} | ||
+ | {{dcla|anchor=3|constexpr=c++20|until=c++26| | ||
+ | template< class InputIt, class OutputIt, class UnaryPred, class T > | ||
+ | OutputIt replace_copy_if | ||
+ | ( InputIt first, InputIt last, OutputIt d_first, | ||
+ | UnaryPred p, const T& new_value ); | ||
+ | }} | ||
+ | {{dcl|since=c++26|1= | ||
+ | template< class InputIt, class OutputIt, class UnaryPred, | ||
+ | class T = typename std::iterator_traits | ||
+ | <OutputIt>::value_type > | ||
+ | constexpr OutputIt replace_copy_if | ||
+ | ( InputIt first, InputIt last, OutputIt d_first, | ||
+ | UnaryPred p, const T& new_value ); | ||
}} | }} | ||
− | {{dcl rev | + | {{dcl rev end}} |
− | template< class | + | {{dcl rev begin|num=4}} |
− | + | {{dcl|since=c++17|until=c++26| | |
− | + | template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, | |
− | + | class UnaryPred, class T > | |
− | + | ForwardIt2 replace_copy_if | |
− | + | ( ExecutionPolicy&& policy, | |
− | + | ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first, | |
+ | UnaryPred p, const T& new_value ); | ||
}} | }} | ||
− | {{dcl | since=c++ | + | {{dcl|since=c++26|1= |
− | template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class | + | template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, |
− | ForwardIt2 replace_copy_if( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last, | + | class UnaryPred, class T = typename std::iterator_traits |
− | + | <ForwardIt2>::value_type > | |
+ | ForwardIt2 replace_copy_if | ||
+ | ( ExecutionPolicy&& policy, | ||
+ | ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first, | ||
+ | UnaryPred p, const T& new_value ); | ||
}} | }} | ||
{{dcl end}} | {{dcl end}} | ||
− | Copies the elements from the range {{ | + | Copies the elements from the range {{range|first|last}} to another range beginning at {{c|d_first}}, while replacing all elements satisfying specific criteria with {{c|new_value}}. |
− | @1@ Replaces all elements that are equal to {{ | + | @1@ Replaces all elements that are equal to {{c|old_value}} (using {{c/core|1=operator==}}). |
− | @3@ Replaces | + | |
− | @2,4@ Same as {{v|1,3}}, but executed according to {{ | + | @3@ Replaces all elements for which predicate {{c|p}} returns {{c|true}}. |
+ | |||
+ | @2,4@ Same as {{v|1,3}}, but executed according to {{c|policy}}. | ||
+ | @@ {{cpp/algorithm/parallel overload precondition|plural=yes}} | ||
+ | |||
+ | If any of the results of the expressions {{c|*first}} and {{c|new_value}} is not [[cpp/iterator#Types and writability|writable]] to {{c|d_first}}, the program is ill-formed. | ||
+ | |||
+ | If the source and destination ranges overlap, the behavior is undefined. | ||
===Parameters=== | ===Parameters=== | ||
{{par begin}} | {{par begin}} | ||
− | {{par | first, last | the range of elements to copy}} | + | {{par|first, last|the range of elements to copy}} |
− | {{par | d_first | the beginning of the destination range}} | + | {{par|d_first|the beginning of the destination range}} |
− | {{par | old_value | the value of elements to replace}} | + | {{par|old_value|the value of elements to replace}} |
{{par exec pol}} | {{par exec pol}} | ||
− | {{par pred1 | p | if the element value should be replaced | p1=InputIt}} | + | {{par pred1|p|if the element value should be replaced|p1=InputIt}} |
− | {{par | new_value | the value to use as replacement}} | + | {{par|new_value|the value to use as replacement}} |
{{par hreq}} | {{par hreq}} | ||
− | {{par req named | InputIt | InputIterator}} | + | {{par req named|InputIt|InputIterator}} |
− | {{par req named | OutputIt | OutputIterator}} | + | {{par req named|OutputIt|OutputIterator}} |
− | {{par req named | ForwardIt1, ForwardIt2 | ForwardIterator}} | + | {{par req named|ForwardIt1, ForwardIt2|ForwardIterator}} |
{{par end}} | {{par end}} | ||
Line 57: | Line 84: | ||
===Complexity=== | ===Complexity=== | ||
− | + | Given {{mathjax-or|\(\scriptsize N\)|N}} as {{c|std::distance(first, last)}}: | |
+ | @1,2@ Exactly {{mathjax-or|\(\scriptsize N\)|N}} comparisons using {{c/core|1=operator==}}. | ||
+ | @3,4@ Exactly {{mathjax-or|\(\scriptsize N\)|N}} applications of the predicate {{c|p}}. | ||
===Exceptions=== | ===Exceptions=== | ||
− | {{cpp/algorithm/ | + | {{cpp/algorithm/parallel exceptions reporting behavior|singular=no}} |
===Possible implementation=== | ===Possible implementation=== | ||
− | {{eq | + | {{eq impl |
− | + | |title1=replace_copy|ver1=1|1= | |
template<class InputIt, class OutputIt, class T> | template<class InputIt, class OutputIt, class T> | ||
OutputIt replace_copy(InputIt first, InputIt last, OutputIt d_first, | OutputIt replace_copy(InputIt first, InputIt last, OutputIt d_first, | ||
const T& old_value, const T& new_value) | const T& old_value, const T& new_value) | ||
{ | { | ||
− | for (; first != last; ++first) | + | for (; first != last; ++first) |
*d_first++ = (*first == old_value) ? new_value : *first; | *d_first++ = (*first == old_value) ? new_value : *first; | ||
− | |||
return d_first; | return d_first; | ||
} | } | ||
− | + | |title2=replace_copy_if|ver2=3|2= | |
− | template<class InputIt, class OutputIt, | + | template<class InputIt, class OutputIt, class UnaryPred, |
− | + | class T = typename std::iterator_traits<ForwardIt>::value_type> | |
OutputIt replace_copy_if(InputIt first, InputIt last, OutputIt d_first, | OutputIt replace_copy_if(InputIt first, InputIt last, OutputIt d_first, | ||
− | + | UnaryPred p, const T& new_value) | |
{ | { | ||
− | for (; first != last; ++first) | + | for (; first != last; ++first) |
− | *d_first++ = p( *first ) ? new_value : *first; | + | *d_first++ = p(*first) ? new_value : *first; |
− | + | ||
return d_first; | return d_first; | ||
} | } | ||
}} | }} | ||
+ | |||
+ | ===Notes=== | ||
+ | {{feature test macro|__cpp_lib_algorithm_default_value_type|value=202403|std=C++26|[[cpp/language/list initialization|List-initialization]] for algorithms {{vl|3,4}}}} | ||
===Example=== | ===Example=== | ||
{{example | {{example | ||
− | + | |code= | |
− | + | ||
#include <algorithm> | #include <algorithm> | ||
+ | #include <complex> | ||
+ | #include <iostream> | ||
#include <vector> | #include <vector> | ||
− | |||
− | |||
− | |||
− | + | void println(const auto& seq) | |
{ | { | ||
− | + | for (const auto& e : seq) | |
− | + | std::cout << e << ' '; | |
− | + | ||
− | + | ||
std::cout << '\n'; | std::cout << '\n'; | ||
} | } | ||
− | | output= | + | |
− | + | int main() | |
+ | { | ||
+ | std::vector<short> src{3, 1, 4, 1, 5, 9, 2, 6, 5}; | ||
+ | println(src); | ||
+ | std::vector<int> dst(src.size()); | ||
+ | std::replace_copy_if(src.cbegin(), src.cend(), | ||
+ | dst.begin(), | ||
+ | [](short n){ return n > 5; }, 0); | ||
+ | println(dst); | ||
+ | |||
+ | std::vector<std::complex<double>> src2{<!---->{1, 3}, {2, 4}, {3, 5}<!---->}, | ||
+ | dst2(src2.size()); | ||
+ | println(src2); | ||
+ | #ifdef __cpp_lib_algorithm_default_value_type | ||
+ | std::replace_copy_if(src2.cbegin(), src2.cend(), dst2.begin(), | ||
+ | [](std::complex<double> z){ return std::abs(z) < 5; }, | ||
+ | {4, 2}); // Possible, since the T is deduced. | ||
+ | #else | ||
+ | std::replace_copy_if(src2.cbegin(), src2.cend(), dst2.begin(), | ||
+ | [](std::complex<double> z){ return std::abs(z) < 5; }, | ||
+ | std::complex<double>{4, 2}); | ||
+ | #endif | ||
+ | println(dst2); | ||
+ | } | ||
+ | |output= | ||
+ | 3 1 4 1 5 9 2 6 5 | ||
+ | 3 1 4 1 5 0 2 0 5 | ||
+ | (1,3) (2,4) (3,5) | ||
+ | (4,2) (4,2) (3,5) | ||
}} | }} | ||
+ | |||
+ | ===Defect reports=== | ||
+ | {{dr list begin}} | ||
+ | {{dr list item|wg=lwg|dr=283|std=C++98|before={{tt|T}} was required to be {{named req|CopyAssignable}} (and {{named req|EqualityComparable}} for<br>{{tt|replace_copy}}), but the value type of {{tt|InputIt}} is not always {{tt|T}}|after=removed the requirement}} | ||
+ | {{dr list item|wg=lwg|dr=337|std=C++98|before={{tt|replace_copy_if}} only required {{tt|InputIt}} to<br>meet the requirements of {{named req|Iterator}}<ref>The actual defect in the C++ standard is that the template parameter {{tt|InputIterator}} was misspecified as {{tt|Iterator}}. This affects the type requirements because the C++ standard states that for the function templates in the algorithms library, the template type parameters whose name ends with {{tt|Iterator}} imply the type requirements of the corresponding iterator categories.</ref>|after=corrected to<br>{{named req|InputIterator}}}} | ||
+ | {{dr list end}} | ||
+ | <references/> | ||
===See also=== | ===See also=== | ||
{{dsc begin}} | {{dsc begin}} | ||
− | {{dsc inc | cpp/algorithm/dsc replace}} | + | {{dsc inc|cpp/algorithm/dsc replace}} |
− | {{dsc inc | cpp/algorithm/dsc remove}} | + | {{dsc inc|cpp/algorithm/dsc remove}} |
− | + | {{dsc inc|cpp/algorithm/ranges/dsc replace_copy}} | |
{{dsc end}} | {{dsc end}} | ||
{{langlinks|de|es|fr|it|ja|pt|ru|zh}} | {{langlinks|de|es|fr|it|ja|pt|ru|zh}} |
Latest revision as of 21:22, 20 May 2024
Defined in header <algorithm>
|
||
template< class InputIt, class OutputIt, class T > OutputIt replace_copy( InputIt first, InputIt last, OutputIt d_first, |
(1) | (constexpr since C++20) |
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T > |
(2) | (since C++17) |
(3) | ||
template< class InputIt, class OutputIt, class UnaryPred, class T > OutputIt replace_copy_if |
(constexpr since C++20) (until C++26) |
|
template< class InputIt, class OutputIt, class UnaryPred, class T = typename std::iterator_traits |
(since C++26) | |
(4) | ||
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class UnaryPred, class T > |
(since C++17) (until C++26) |
|
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class UnaryPred, class T = typename std::iterator_traits |
(since C++26) | |
Copies the elements from the range [
first,
last)
to another range beginning at d_first, while replacing all elements satisfying specific criteria with new_value.
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 any of the results of the expressions *first and new_value is not writable to d_first, the program is ill-formed.
If the source and destination ranges overlap, the behavior is undefined.
Contents |
[edit] Parameters
first, last | - | the range of elements to copy |
d_first | - | the beginning of the destination range |
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 |
new_value | - | the value to use as replacement |
Type requirements | ||
-InputIt must meet the requirements of LegacyInputIterator.
| ||
-OutputIt must meet the requirements of LegacyOutputIterator.
| ||
-ForwardIt1, ForwardIt2 must meet the requirements of LegacyForwardIterator.
|
[edit] Return value
Iterator to the element past the last element copied.
[edit] Complexity
Given N as std::distance(first, last):
[edit] 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 otherExecutionPolicy
, the behavior is implementation-defined. - If the algorithm fails to allocate memory, std::bad_alloc is thrown.
[edit] Possible implementation
replace_copy |
---|
template<class InputIt, class OutputIt, class T> OutputIt replace_copy(InputIt first, InputIt last, OutputIt d_first, const T& old_value, const T& new_value) { for (; first != last; ++first) *d_first++ = (*first == old_value) ? new_value : *first; return d_first; } |
replace_copy_if |
template<class InputIt, class OutputIt, class UnaryPred, class T = typename std::iterator_traits<ForwardIt>::value_type> OutputIt replace_copy_if(InputIt first, InputIt last, OutputIt d_first, UnaryPred p, const T& new_value) { for (; first != last; ++first) *d_first++ = p(*first) ? new_value : *first; return d_first; } |
[edit] Notes
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_lib_algorithm_default_value_type |
202403 | (C++26) | List-initialization for algorithms (3,4) |
[edit] Example
#include <algorithm> #include <complex> #include <iostream> #include <vector> void println(const auto& seq) { for (const auto& e : seq) std::cout << e << ' '; std::cout << '\n'; } int main() { std::vector<short> src{3, 1, 4, 1, 5, 9, 2, 6, 5}; println(src); std::vector<int> dst(src.size()); std::replace_copy_if(src.cbegin(), src.cend(), dst.begin(), [](short n){ return n > 5; }, 0); println(dst); std::vector<std::complex<double>> src2{{1, 3}, {2, 4}, {3, 5}}, dst2(src2.size()); println(src2); #ifdef __cpp_lib_algorithm_default_value_type std::replace_copy_if(src2.cbegin(), src2.cend(), dst2.begin(), [](std::complex<double> z){ return std::abs(z) < 5; }, {4, 2}); // Possible, since the T is deduced. #else std::replace_copy_if(src2.cbegin(), src2.cend(), dst2.begin(), [](std::complex<double> z){ return std::abs(z) < 5; }, std::complex<double>{4, 2}); #endif println(dst2); }
Output:
3 1 4 1 5 9 2 6 5 3 1 4 1 5 0 2 0 5 (1,3) (2,4) (3,5) (4,2) (4,2) (3,5)
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
LWG 283 | C++98 | T was required to be CopyAssignable (and EqualityComparable forreplace_copy ), but the value type of InputIt is not always T
|
removed the requirement |
LWG 337 | C++98 | replace_copy_if only required InputIt tomeet the requirements of LegacyIterator[1] |
corrected to LegacyInputIterator |
- ↑ The actual defect in the C++ standard is that the template parameter
InputIterator
was misspecified asIterator
. This affects the type requirements because the C++ standard states that for the function templates in the algorithms library, the template type parameters whose name ends withIterator
imply the type requirements of the corresponding iterator categories.
[edit] See also
replaces all values satisfying specific criteria with another value (function template) | |
removes elements satisfying specific criteria (function template) | |
(C++20)(C++20) |
copies a range, replacing elements satisfying specific criteria with another value (niebloid) |