std::ranges:: remove, std::ranges:: remove_if
|
헤더 파일에 정의됨
<algorithm>
|
||
|
호출 시그니처
|
||
| (1) | ||
|
template
<
std::
permutable
I,
std::
sentinel_for
<
I
>
S,
class
T,
class
Proj
=
std::
identity
>
|
(C++20부터)
(C++26까지) |
|
|
template
<
std::
permutable
I,
std::
sentinel_for
<
I
>
S,
class
Proj
=
std::
identity
,
|
(C++26부터) | |
| (2) | ||
|
template
<
ranges::
forward_range
R,
class
T,
class
Proj
=
std::
identity
>
|
(C++20부터)
(C++26까지) |
|
|
template
<
ranges::
forward_range
R,
class
Proj
=
std::
identity
,
|
(C++26부터) | |
|
template
<
std::
permutable
I,
std::
sentinel_for
<
I
>
S,
class
Proj
=
std::
identity
,
|
(3) | (C++20 이후) |
|
template
<
ranges::
forward_range
R,
class
Proj
=
std::
identity
,
|
(4) | (C++20 이후) |
범위
[
first
,
last
)
에서 특정 조건을 만족하는 모든 요소를 제거하고,
[
ret
,
last
)
부분 범위를 반환합니다. 여기서
ret
는 범위의 새로운 끝을 가리키는 past-the-end iterator입니다.
제거는 범위 내 요소들을 이동 대입(move assignment)을 통해 이동시킴으로써 수행되며, 제거되지 않을 요소들이 범위의 시작 부분에 나타나도록 합니다. 남아 있는 요소들의 상대적 순서는 유지되며 컨테이너의 물리적 크기는 변경되지 않습니다. 새로운 논리적 끝과 범위의 물리적 끝 사이에 있는 요소를 가리키는 반복자들은 여전히 역참조 가능하지만, 요소 자체는 지정되지 않은 값을 가집니다 ( MoveAssignable 사후 조건에 따름).
이 페이지에서 설명하는 함수형 개체들은 algorithm function objects (일반적으로 niebloids 로 알려진)입니다. 즉:
- 명시적 템플릿 인수 목록은 이들 중 어느 것을 호출할 때도 지정할 수 없습니다.
- 이들 중 어느 것도 인수 의존적查找 에 보이지 않습니다.
- 이들 중 어느 것이 함수 호출 연산자의 왼쪽 이름으로 일반 비한정查找 에 의해 발견될 때, 인수 의존적查找 가 억제됩니다.
목차 |
매개변수
| first, last | - | 처리할 요소들의 범위 를 정의하는 반복자-감시자 쌍 |
| r | - | 처리할 요소들의 범위 |
| value | - | 제거할 요소의 값 |
| pred | - | 투영된 요소들에 적용할 조건자 |
| proj | - | 요소들에 적용할 투영 |
반환값
{
ret, last
}
, 여기서
[
first
,
ret
)
는 제거 후 결과적인 부분 범위이며, 부분 범위
[
ret
,
last
)
내의 요소들은 모두 유효하지만 지정되지 않은 상태에 있습니다. 즉,
[
ret
,
last
)
는 삭제될 부분 범위입니다.
복잡도
정확히 N 번의 해당 predicate와 모든 projection이 적용되며, 여기서 N = ranges:: distance ( first, last ) 입니다. 또한 최악의 경우 N - 1 번의 move 연산이 수행됩니다.
참고 사항
ranges::remove
에 대한 호출은 일반적으로 컨테이너의
erase
멤버 함수 호출이 뒤따르며, 이는 지정되지 않은 값을 지우고 컨테이너의
물리적
크기를 새로운
논리적
크기에 맞게 축소합니다. 이 두 가지 호출을 함께 사용하면 소위
erase-remove idiom
이 구성되며, 이는 모든 표준
시퀀스
컨테이너에 대해
오버로드
를 갖는 자유 함수
std::erase
또는
모든
표준 컨테이너에 대해
오버로드
를 갖는
std::erase_if
를 통해 달성할 수 있습니다.
유사한 이름의 컨테이너 멤버 함수 list::remove , list::remove_if , forward_list::remove , 그리고 forward_list::remove_if 는 제거된 요소들을 삭제합니다.
이러한 알고리즘은 일반적으로 std::set 및 std::map 같은 연관 컨테이너와 함께 사용할 수 없습니다. 왜냐하면 이들의 반복자 타입이 MoveAssignable 타입으로 역참조되지 않기 때문입니다(이러한 컨테이너의 키는 수정할 수 없습니다).
ranges::remove
가
value
를 참조로 받기 때문에, 이 값이 범위
[
first
,
last
)
의 요소를 참조하는 경우 예상치 못한 동작이 발생할 수 있습니다.
가능한 구현
| remove (1,2) |
|---|
struct remove_fn { template<std::permutable I, std::sentinel_for<I> S, class Proj = std::identity, class T = std::projected_value_t<I, Proj>> requires std::indirect_binary_predicate <ranges::equal_to, std::projected<I, Proj>, const T*> constexpr ranges::subrange<I> operator()(I first, S last, const T& value, Proj proj = {}) const { first = ranges::find(std::move(first), last, value, proj); if (first != last) { for (I i{std::next(first)}; i != last; ++i) if (value != std::invoke(proj, *i)) { *first = ranges::iter_move(i); ++first; } } return {first, last}; } template<ranges::forward_range R, class Proj = std::identity, class T = std::projected_value_t<ranges::iterator_t<R>, Proj>> requires std::permutable<ranges::iterator_t<R>> && std::indirect_binary_predicate <ranges::equal_to, std::projected<ranges::iterator_t<R>, Proj>, const T*> constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, const T& value, Proj proj = {}) const { return (*this)(ranges::begin(r), ranges::end(r), value, std::move(proj)); } }; inline constexpr remove_fn remove {}; |
| remove_if (3,4) |
struct remove_if_fn { template<std::permutable I, std::sentinel_for<I> S, class Proj = std::identity, std::indirect_unary_predicate<std::projected<I, Proj>> Pred> constexpr ranges::subrange<I> operator()(I first, S last, Pred pred, Proj proj = {}) const { first = ranges::find_if(std::move(first), last, pred, proj); if (first != last) { for (I i{std::next(first)}; i != last; ++i) if (!std::invoke(pred, std::invoke(proj, *i))) { *first = ranges::iter_move(i); ++first; } } return {first, last}; } template<ranges::forward_range R, class Proj = std::identity, std::indirect_unary_predicate <std::projected<ranges::iterator_t<R>, Proj>> Pred> requires std::permutable<ranges::iterator_t<R>> constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const { return (*this)(ranges::begin(r), ranges::end(r), pred, std::move(proj)); } }; inline constexpr remove_if_fn remove_if {}; |
참고 사항
| 기능 테스트 매크로 | 값 | 표준 | 기능 |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type
|
202403
|
(C++26) | 목록 초기화 for algorithms ( 1,2 ) |
예제
#include <algorithm> #include <cassert> #include <complex> #include <cctype> #include <iomanip> #include <iostream> #include <string> #include <string_view> #include <vector> int main() { std::string v1{"진단 불필요"}; std::cout << std::quoted(v1) << " (v1, 크기: " << v1.size() << ")\n"; const auto ret = std::ranges::remove(v1, ' '); std::cout << std::quoted(v1) << " (v1 after `remove`, size: " << v1.size() << ")\n"; std::cout << ' ' << std::string(std::distance(v1.begin(), ret.begin()), '^') << '\n'; v1.erase(ret.begin(), ret.end()); std::cout << std::quoted(v1) << " (v1 `erase` 이후, 크기: " << v1.size() << ")\n\n"; // 사용자 정의 단항 조건자를 사용한 remove_if: auto rm = [](char c) { return !std::isupper(c); }; std::string v2{"Substitution Failure Is Not An Error"}; std::cout << std::quoted(v2) << " (v2, 크기: " << v2.size() << ")\n"; const auto [first, last] = std::ranges::remove_if(v2, rm); std::cout << std::quoted(v2) << " (v2 after `remove_if`, size: " << v2.size() << ")\n"; std::cout << ' ' << std::string(std::distance(v2.begin(), first), '^') << '\n'; v2.erase(first, last); std::cout << std::quoted(v2) << " (v2 `erase` 이후, 크기: " << v2.size() << ")\n\n"; // `remove_if`에 의해 수정되는 컨테이너의 뷰 생성: for (std::string s : {"Small Object Optimization", "비타입 템플릿 매개변수"}) std::cout << std::quoted(s) << " => " << std::string_view{begin(s), std::ranges::remove_if(s, rm).begin()} << '\n'; std::vector<std::complex<double>> nums{{2, 2}, {1, 3}, {4, 8}}; #ifdef __cpp_lib_algorithm_default_value_type auto e = std::ranges::remove(nums, {1, 3}); // T가 추론됨 #else auto e = std::ranges::remove(nums, std::complex<double>{1, 3}); #endif nums.erase(e.begin(), e.end()); assert((nums == std::vector<std::complex<double>>{{2, 2}, {4, 8}})); }
가능한 출력:
"No _ Diagnostic _ Required" (v1, 크기: 26) "No_Diagnostic_Requiredired" (v1 `remove` 후, 크기: 26) ^^^^^^^^^^^^^^^^^^^^^^ "No_Diagnostic_Required" (v1 `erase` 후, 크기: 22) "Substitution Failure Is Not An Error" (v2, 크기: 36) "SFINAEtution Failure Is Not An Error" (v2 `remove_if` 후, 크기: 36) ^^^^^^ "SFINAE" (v2 `erase` 후, 크기: 6) "Small Object Optimization" => SOO "Non-Type Template Parameter" => NTTP
참고 항목
|
(C++20)
(C++20)
|
특정 조건을 만족하는 요소들을 생략하고 범위의 요소들을 복사합니다
(알고리즘 함수 객체) |
|
(C++20)
|
범위에서 연속된 중복 요소들을 제거합니다
(알고리즘 함수 객체) |
|
특정 조건을 만족하는 요소들을 제거합니다
(함수 템플릿) |