C++23에서는 범위(Range) 라이브러리에 다양한 알고리즘들이 추가되어, 데이터 처리 파이프라인을 한층 더 풍부하게 구성할 수 있게 되었습니다. 그중에서도 std::ranges::drop_last와 std::ranges::drop_last_while 함수는 범위의 끝부분에서 특정 개수나 조건에 맞는 원소들을 제거(drop) 하는 기능을 제공합니다. 이를 통해 기존의 std::ranges::drop가 범위의 앞부분을 제거하는 것에 더해, 뒷부분에 대해 유사한 조작을 간단하게 수행할 수 있게 되었습니다.
이번 글에서는 std::ranges::drop_last와 std::ranges::drop_last_while의 개념과 사용법, 그리고 이전 방식과 비교하여 어떤 점이 개선되었는지 살펴보겠습니다.
std::ranges::drop_last란 무엇인가요?
- std::ranges::drop_last(rng, n): 범위 rng의 끝부분에서 n개의 원소를 제거한 새로운 범위를 반환합니다.
- 예를 들어 [1,2,3,4,5]에서 drop_last(..., 2)를 하면 [1,2,3]을 얻을 수 있습니다.
std::ranges::drop_last_while란 무엇인가요?
- std::ranges::drop_last_while(rng, pred): 범위 rng를 뒤에서 앞으로 탐색하면서, 조건자 pred를 만족하는 원소를 계속 제거합니다. pred를 만족하지 않는 원소를 만나는 순간 그 앞부분의 범위를 반환합니다.
- 예를 들어 [10,20,30,40,0,0]에 대해 뒤에서부터 pred(x) = (x == 0) 검사 시, drop_last_while(..., pred)를 하면 뒷부분의 0,0을 제거하여 [10,20,30,40]를 반환합니다.
이전 버전에서는 어떻게 했나요?
C++20까지는 범위의 끝부분에서 원소를 제거하기 위해 다음과 같은 방법이 필요했습니다.
예제: 기존 방식(C++20까지)
#include <vector>
#include <iostream>
// 뒷부분 2개 원소 제거 예
int main() {
std::vector<int> vec = {1,2,3,4,5};
// drop_last와 유사한 동작
// vec.end()-2까지를 서브 범위로 얻거나, resize etc.
vec.resize(vec.size() - 2); // vec: {1,2,3}
// 조건 기반 제거 (drop_last_while 유사)
// 뒤에서부터 조건 만족하는 원소 제거
while (!vec.empty() && vec.back() == 0) {
vec.pop_back();
}
return 0;
}
- 문제점:
- 단순히 뒷부분 원소를 제거하는데 resize나 pop_back 반복 등 별도 로직 필요
- 조건 기반 제거 시 iterator 또는 pop_back 반복 필요, 함수형 스타일 파이프라인에서 표현하기 어려움
C++23의 std::ranges::drop_last 사용 예제
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1,2,3,4,5};
// 뒤에서 2개 원소 제거
auto dropped = std::ranges::drop_last(vec, 2);
for (int x : dropped) {
std::cout << x << ' '; // 출력: 1 2 3
}
return 0;
}
- 한 번의 함수 호출로 뒷부분 n개 원소 제거 가능, 가독성 향상.
C++23의 std::ranges::drop_last_while 사용 예제
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> data = {10,20,30,40,0,0};
// 뒤에서부터 0인 원소 제거
auto cleaned = std::ranges::drop_last_while(data, [](int x){ return x == 0; });
for (int x : cleaned) {
std::cout << x << ' '; // 출력: 10 20 30 40
}
return 0;
}
- 조건자 하나로 뒤에서 조건을 만족하는 원소들을 제거, 이전에는 pop_back 반복 또는 reverse iterator로 구현해야 했던 로직 단순화.
어떻게 좋아졌나요?
- 코드 간결화: 범위의 끝부분 처리 로직을 한 번의 함수 호출로 명확하게 표현.
- 함수형 프로그래밍 스타일 강화: 다른 범위 어댑터(transform, filter, take 등)와 조합하여 데이터 파이프라인에서 뒷부분 정리 로직을 자연스럽게 추가.
- 가독성 향상: drop_last, drop_last_while라는 이름에서 의도를 명확히 파악, iterator 수동 조작 불필요.
- 유연성 증가: drop_last_while를 통해 조건 기반 로직 자유롭게 적용, 간단히 조건자 변경으로 새로운 제거 로직 적용.
주의 사항
- drop_last 시 경계 상황: n이 범위 길이보다 크면 빈 범위 반환. 코드 로직에서 n 값 주의 필요.
- drop_last_while 시 조건자 정의: 조건자가 참을 반환하는 동안만 뒤에서 제거하므로, 적절한 조건자 로직 필수.
- C++23 지원 여부: C++23 기능이므로, 지원하는 컴파일러와 표준 라이브러리 필요.
요약
C++23의 std::ranges::drop_last와 std::ranges::drop_last_while는 범위의 끝부분 원소를 제거하는 작업을 간결하고 직관적으로 만듭니다. 이전에는 iterator 조작이나 반복적 pop_back 등의 작업이 필요했지만, 이제는 함수 한 번의 호출로 이 의도를 명확히 구현할 수 있어 코드 가독성과 유지보수성, 생산성이 향상됩니다.
참고 자료:
반응형
'개발 이야기 > C++' 카테고리의 다른 글
[C++23 새기능 소개] std::views::repeat와 std::views::repeat_n (1) | 2024.12.12 |
---|---|
[C++23 새기능 소개] std::views::common (0) | 2024.12.12 |
[C++23 새기능 소개] std::byteswap (0) | 2024.12.12 |
C++20과 C++23을 활용한 “파이썬스러운” API 구현 #14: groupby, permutations, product (0) | 2024.12.12 |
C++20과 C++23을 활용한 “파이썬스러운” API 구현 #13: takewhile, dropwhile, accumulate (0) | 2024.12.12 |