C++ Views | "뷰" 가이드

C++ Views | "뷰" 가이드

이 글의 핵심

C++ Views에 대한 실전 가이드입니다. 개념부터 실무 활용까지 예제와 함께 상세히 설명합니다.

Views란?

지연 평가 범위 (C++20)

#include <ranges>

std::vector<int> v = {1, 2, 3, 4, 5};

// 뷰: 복사 없음
auto filtered = v | std::views::filter( { return x > 2; });

// 순회 시 평가
for (int x : filtered) {
    std::cout << x << " ";  // 3 4 5
}

기본 뷰

namespace vws = std::views;

// filter: 조건 필터
vws::filter( { return x % 2 == 0; })

// transform: 변환
vws::transform( { return x * 2; })

// take: 처음 n개
vws::take(5)

// drop: 처음 n개 제외
vws::drop(3)

// reverse: 역순
vws::reverse

실전 예시

예시 1: filter

#include <ranges>
#include <vector>

std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 짝수만
auto evens = numbers | std::views::filter( { 
    return x % 2 == 0; 
});

for (int x : evens) {
    std::cout << x << " ";  // 2 4 6 8 10
}

예시 2: transform

std::vector<int> numbers = {1, 2, 3, 4, 5};

// 제곱
auto squares = numbers | std::views::transform( { 
    return x * x; 
});

for (int x : squares) {
    std::cout << x << " ";  // 1 4 9 16 25
}

예시 3: take & drop

std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 처음 5개
auto first5 = numbers | std::views::take(5);
// 1 2 3 4 5

// 처음 3개 제외
auto skip3 = numbers | std::views::drop(3);
// 4 5 6 7 8 9 10

// 조합: 3개 제외 후 5개
auto middle = numbers | std::views::drop(3) | std::views::take(5);
// 4 5 6 7 8

예시 4: 복합 파이프라인

#include <ranges>
#include <vector>
#include <string>

struct Person {
    std::string name;
    int age;
};

std::vector<Person> people = {
    {"Alice", 25},
    {"Bob", 30},
    {"Charlie", 35},
    {"David", 40}
};

// 30세 이상 -> 이름만 -> 대문자 -> 처음 2개
auto result = people
    | std::views::filter( { return p.age >= 30; })
    | std::views::transform( { return p.name; })
    | std::views::transform( {
        std::string upper = name;
        for (char& c : upper) c = std::toupper(c);
        return upper;
    })
    | std::views::take(2);

for (const auto& name : result) {
    std::cout << name << std::endl;  // BOB, CHARLIE
}

조건부 뷰

namespace vws = std::views;

std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// take_while: 조건 만족하는 동안
auto lessThan5 = v | vws::take_while( { return x < 5; });
// 1 2 3 4

// drop_while: 조건 만족하는 동안 제외
auto from5 = v | vws::drop_while( { return x < 5; });
// 5 6 7 8 9 10

자주 발생하는 문제

문제 1: 수명

// ❌ 댕글링 참조
auto getView() {
    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 view = v | std::views::filter( { return x > 1; });
    std::ranges::copy(view, std::back_inserter(result));
    return result;
}

문제 2: 복사

// 뷰는 복사 안 함
std::vector<int> v = {1, 2, 3};
auto view = v | std::views::transform( { return x * 2; });

v[0] = 10;

// view는 v 참조
for (int x : view) {
    std::cout << x << " ";  // 20 4 6
}

문제 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 r1 = v
    | std::views::transform( { return x * x; })  // 10개 제곱
    | std::views::take(3);  // 3개만 사용

// ✅ 효율적
auto r2 = v
    | std::views::take(3)  // 3개만
    | std::views::transform( { return x * x; });  // 3개만 제곱

뷰 조합

namespace vws = std::views;

std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 여러 뷰 조합
auto result = v
    | vws::filter( { return x % 2 == 0; })  // 짝수
    | vws::transform( { return x * x; })    // 제곱
    | vws::reverse                                    // 역순
    | vws::take(3);                                   // 처음 3개

// 100 64 36

FAQ

Q1: Views는?

A: 지연 평가 범위.

Q2: 지연 평가?

A: 순회 시 계산.

Q3: 복사?

A: 안 함. 참조.

Q4: 파이프라인?

A: | 연산자로 조합.

Q5: 성능?

A:

  • 복사 없음
  • 지연 평가
  • 순서 중요

Q6: 학습 리소스는?

A:

  • “C++20 Ranges”
  • “C++20 The Complete Guide”
  • cppreference.com

같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.

  • C++ Ranges | “범위 라이브러리” 가이드
  • C++ Ranges | “함수형 프로그래밍” C++20 가이드
  • C++ subrange | “부분 범위” 가이드

관련 글

  • C++ Ranges 파이프라인·뷰 |
  • C++ Ranges 기본 개념 |
  • C++ Generator 완벽 가이드 | co_yield로 lazy 시퀀스·무한 수열·파이프라인 만들기
  • C++20 Ranges | begin/end 반복 탈출하고 ranges 알고리즘 쓰기
  • C++ Ranges Views와 파이프라인 | 지연 연산으로 효율적으로 다루기 [#25-2]