C++ Ranges 기본 개념 | "범위 라이브러리" 가이드

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]