C++ Ranges 기본 개념 | "범위 라이브러리" 가이드
이 글의 핵심
C++ Ranges에 대해 정리한 개발 블로그 글입니다. #include <ranges> #include <vector>
Ranges란?
C++20 범위 라이브러리
#include <ranges>
#include <vector>
std::vector<int> v = {1, 2, 3, 4, 5};
// 파이프라인
auto result = v
| std::views::filter( { return x % 2 == 0; })
| std::views::transform( { return x * 2; });
기본 개념
#include <ranges>
namespace rng = std::ranges;
namespace vws = std::views;
std::vector<int> v = {1, 2, 3, 4, 5};
// 뷰: 지연 평가
auto filtered = v | vws::filter( { return x > 2; });
// 실제 평가는 순회 시
for (int x : filtered) {
std::cout << x << " "; // 3 4 5
}
실전 예시
예시 1: 파이프라인
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 짝수만 필터 -> 제곱 -> 처음 3개
auto result = numbers
| std::views::filter( { return x % 2 == 0; })
| std::views::transform( { return x * x; })
| std::views::take(3);
for (int x : result) {
std::cout << x << " "; // 4 16 36
}
}
예시 2: 문자열 처리
#include <ranges>
#include <string>
#include <cctype>
std::string text = "Hello World 2026";
// 알파벳만 필터 -> 대문자 변환
auto result = text
| std::views::filter( { return std::isalpha(c); })
| std::views::transform( { return std::toupper(c); });
for (char c : result) {
std::cout << c; // HELLOWORLD
}
예시 3: 범위 생성
#include <ranges>
// iota: 순차 생성
auto numbers = std::views::iota(1, 11); // 1~10
// repeat (C++23)
// auto zeros = std::views::repeat(0) | std::views::take(5);
// empty
auto empty = std::views::empty<int>;
예시 4: 중첩 범위
#include <ranges>
#include <vector>
std::vector<std::vector<int>> matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 평탄화
auto flattened = matrix | std::views::join;
for (int x : flattened) {
std::cout << x << " "; // 1 2 3 4 5 6 7 8 9
}
주요 뷰
namespace vws = std::views;
// 필터
vws::filter(pred)
// 변환
vws::transform(func)
// 개수 제한
vws::take(n)
vws::drop(n)
// 조건 제한
vws::take_while(pred)
vws::drop_while(pred)
// 역순
vws::reverse
// 분할
vws::split(delimiter)
// 평탄화
vws::join
// 생성
vws::iota(start, end)
자주 발생하는 문제
문제 1: 지연 평가
std::vector<int> v = {1, 2, 3};
auto filtered = v | std::views::filter( { return x > 1; });
// v 수정
v.push_back(4);
// ❌ 댕글링 참조
// filtered는 v를 참조 (복사 아님)
// ✅ 즉시 평가
std::vector<int> result;
std::ranges::copy(filtered, std::back_inserter(result));
문제 2: 수명
// ❌ 임시 객체
auto getFiltered() {
std::vector<int> v = {1, 2, 3};
return v | std::views::filter( { return x > 1; });
// v 소멸 -> 댕글링
}
// ✅ 소유
auto getFiltered() {
std::vector<int> v = {1, 2, 3};
std::vector<int> result;
auto filtered = v | std::views::filter( { return x > 1; });
std::ranges::copy(filtered, std::back_inserter(result));
return result;
}
문제 3: 성능
// 뷰는 지연 평가
auto view = v | std::views::filter(pred) | std::views::transform(func);
// 여러 번 순회 시 매번 재계산
for (int x : view) { /* ... */ } // 계산
for (int x : view) { /* ... */ } // 다시 계산
// ✅ 캐싱 필요 시 즉시 평가
std::vector<int> cached(view.begin(), view.end());
문제 4: 파이프 순서
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// ❌ 비효율
auto result1 = v
| std::views::transform( { return x * x; }) // 모든 요소 제곱
| std::views::take(3); // 처음 3개만 사용
// ✅ 효율적
auto result2 = v
| std::views::take(3) // 처음 3개만
| std::views::transform( { return x * x; }); // 3개만 제곱
범위 알고리즘
#include <ranges>
#include <algorithm>
std::vector<int> v = {3, 1, 4, 1, 5};
// ranges 알고리즘
std::ranges::sort(v);
auto it = std::ranges::find(v, 4);
FAQ
Q1: Ranges는?
A: C++20. 범위 기반 프로그래밍.
Q2: 뷰는?
A: 지연 평가 범위.
Q3: 파이프라인?
A: | 연산자로 조합.
Q4: 장점은?
A:
- 가독성
- 지연 평가
- 조합 가능
Q5: 주의점?
A: 수명, 댕글링 참조.
Q6: 학습 리소스는?
A:
- “C++20 The Complete Guide”
- “C++ Ranges”
- cppreference.com
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ Views | “뷰” 가이드
- C++ Ranges | “함수형 프로그래밍” C++20 가이드
- C++ Range Adaptor | “범위 어댑터” 가이드
관련 글
- C++ Ranges 파이프라인·뷰 |
- C++ Views |
- C++ Range Adaptor |
- C++20 Ranges | begin/end 반복 탈출하고 ranges 알고리즘 쓰기
- C++ Ranges Views와 파이프라인 | 지연 연산으로 효율적으로 다루기 [#25-2]