[C++23 새기능 소개] std::views::stride

C++23에서는 범위(Range) 라이브러리를 더욱 강력하고 유연하게 만들기 위해 다양한 뷰(View) 어댑터가 추가되었습니다. 그중 하나인 std::views::stride는 입력 범위에서 일정한 간격으로 원소를 선택하여 부분 범위를 구성하는 뷰 어댑터입니다. 이를 통해 예를 들어 [1,2,3,4,5,6,7,8] 범위에서 stride(3)를 적용하면 [1,4,7]와 같이 매 3번째 원소를 추출할 수 있습니다.

 

이번 글에서는 std::views::stride의 개념과 사용법, 그리고 이전 방식과 비교하여 어떠한 개선점을 제공하는지 알아보겠습니다.

 

std::views::stride란 무엇인가요?

std::views::stride(n)는 입력 범위에서 시작 원소를 포함해 매 n번째 원소를 선택하는 뷰 어댑터입니다. 예를 들어:

  • 원본 범위: [0,1,2,3,4,5,6]
  • std::views::stride(2) 적용 시: [0,2,4,6]
  • std::views::stride(3) 적용 시: [0,3,6]

이처럼 stride를 사용하면 특정 간격으로 샘플링(sampling)하거나, 긴 시퀀스에서 특정 패턴에 따라 원소를 추출하는 로직을 매우 간단히 표현할 수 있습니다.

이전 버전에서는 어떻게 했나요?

C++20까지는 범위에서 일정 간격으로 원소를 추출하려면 인덱스 계산이나 iterator를 수동으로 조작해야 했습니다.

예제: 기존 방식(C++20까지)

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {0,1,2,3,4,5,6,7,8};
    int step = 3;

    // step 간격으로 원소 접근
    for (std::size_t i = 0; i < vec.size(); i += step) {
        std::cout << vec[i] << ' ';
    }
    // 출력: 0 3 6
    return 0;
}
  • 문제점: 인덱스 계산 코드 필요, 파이프라인 형식으로 다른 뷰와 결합하기 어려움.

C++23의 std::views::stride 사용 예제

#include <ranges>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {0,1,2,3,4,5,6,7,8};

    // stride(3)을 적용해 매 3번째 원소 추출
    auto strided = vec | std::views::stride(3);

    for (int x : strided) {
        std::cout << x << ' '; // 출력: 0 3 6
    }

    return 0;
}
  • stride(3)를 한 번의 호출로 적용할 수 있어 코드가 매우 간결해집니다.

어떻게 좋아졌나요?

  • 코드 간결성: 인덱스 계산이나 별도의 iterator 조작 없이 한 번의 뷰 어댑터 호출로 일정 간격 추출 가능.
  • 가독성 향상: stride라는 이름에서 바로 의도를 파악할 수 있으므로, 로직 이해가 쉬워짐.
  • 함수형 프로그래밍 스타일 강화: 다른 범위 어댑터(filter, transform, take, join 등)와 쉽게 결합 가능해, 복잡한 데이터 파이프라인에서 특정 간격으로 원소를 샘플링하는 로직을 손쉽게 표현.
  • 유연성 증대: stride 인자를 바꿔가며 간단히 간격 조정 가능.

상세한 예제와 비교

다른 뷰와 조합

#include <ranges>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> data = {10,20,30,40,50,60,70,80};

    // 짝수 인덱스 원소만 추출 후, 각 원소에 2배 연산
    // 여기서 stride(2)로 매 2번째 원소(인덱스 0,2,4...) 선택
    auto processed = data
        | std::views::stride(2)
        | std::views::transform([](int x) { return x * 2; });

    for (int x : processed) {
        std::cout << x << ' '; // 출력: 20 60 100 140
    }

    return 0;
}
  • stride(2)로 짝수 인덱스 원소 추출 -> transform으로 2배 -> 가독성 좋고 유지보수 쉬운 함수형 파이프라인 구현.

주의 사항

  • 인덱스 범위 주의: stride(n) 적용 시, 범위 끝부분에 남는 원소가 n개보다 적을 경우, 남는 만큼만 추출.
  • C++23 지원 여부: C++23 기능이므로, 지원하는 컴파일러와 표준 라이브러리 필요.
  • 성능 고려: 큰 범위에서 stride 사용 시 성능에 영향, 하지만 lazy evaluation을 통해 불필요한 연산 최소화.

요약

C++23의 std::views::stride는 범위에서 일정 간격으로 원소를 선택하는 뷰 어댑터로, 인덱스 계산 등 번거로운 과정을 없이도 샘플링이나 부분 선택 로직을 명확하고 간단하게 표현할 수 있습니다. 다른 뷰 어댑터와 쉽게 결합하여 복잡한 데이터 처리 파이프라인을 한 줄에 구현할 수 있어, 코드 가독성과 유지보수성, 생산성을 크게 향상시킵니다.

 

참고 자료:

반응형