C++23에서는 범위(Range) 라이브러리를 더욱 강화하기 위해 다양한 뷰(View) 어댑터가 추가되었습니다. 그중 std::views::repeat와 std::views::repeat_n는 특정 값을 무한히 반복하거나, 지정된 횟수만큼 반복하는 시퀀스를 손쉽게 만들 수 있도록 해주는 뷰 어댑터입니다. 이를 통해 반복적인 데이터 소스를 간편하게 생성할 수 있으며, 다른 범위 어댑터와 결합하여 여러 가지 흥미로운 데이터 처리 파이프라인을 구성할 수 있습니다.
이번 글에서는 std::views::repeat와 std::views::repeat_n의 개념과 사용법, 그리고 이전 방식과 비교하여 어떠한 개선점을 제공하는지 알아보겠습니다.
std::views::repeat란 무엇인가요?
- std::views::repeat(value): 단일 값 value를 무한히 반복하는 범위를 생성합니다.
예를 들어, std::views::repeat(42)를 하면 [42, 42, 42, ...]와 같은 무한 시퀀스를 얻을 수 있습니다.
이 무한 시퀀스는 게으른(lazy) 방식으로 값이 필요할 때마다 같은 값을 생성하므로, 메모리 오버헤드 없이 무한 시퀀스를 표현할 수 있습니다. 물론 실제 프로그램에서는 무한 시퀀스를 모두 소비하지 않도록 다른 연산자(take, drop 등)와 결합해야 합니다.
std::views::repeat_n란 무엇인가요?
- std::views::repeat_n(value, n): 단일 값 value를 정확히 n번 반복하는 유한 시퀀스를 생성합니다.
예를 들어, std::views::repeat_n(42, 3)를 하면 [42, 42, 42]라는 유한 시퀀스를 얻을 수 있습니다.
이로써 특정한 값이나 상수를 여러 번 반복하는 범위를 손쉽게 만들 수 있어, 테스트용 데이터나 일정한 패턴을 생성하는데 유용합니다.
이전 버전에서는 어떻게 했나요?
C++20까지는 특정 값을 반복하는 시퀀스를 만들기 위해 다음과 같은 방법을 사용했습니다.
예제: 기존 방식(C++20까지)
#include <vector>
#include <iostream>
// 특정 값을 n번 반복하는 벡터 생성
int main() {
int value = 42;
int n = 3;
std::vector<int> vec(n, value); // 벡터 생성자로 해결
// 하지만 파이프라인에서 repeat 형태의 범위를 만들려면 직접 range 생성 필요
// 무한 시퀀스는 별도 이터레이터 래퍼 만들거나 해야 함.
for (int x : vec) {
std::cout << x << ' ';
}
// 출력: 42 42 42
return 0;
}
- 무한 반복 시퀀스를 만들려면 사용자 정의 이터레이터 작성 혹은 while(true)루프 등 비우아한 방법 필요.
C++23의 std::views::repeat 사용 예제
#include <ranges>
#include <iostream>
int main() {
// 무한히 10을 반복하는 시퀀스
auto infinite_tens = std::views::repeat(10);
// 무한 시퀀스에서 처음 5개 원소만 취하기
for (int x : infinite_tens | std::views::take(5)) {
std::cout << x << ' '; // 출력: 10 10 10 10 10
}
return 0;
}
- repeat와 take를 결합해 원하는 개수만큼 무한 시퀀스 소비 가능.
C++23의 std::views::repeat_n 사용 예제
#include <ranges>
#include <iostream>
int main() {
// 42를 3번 반복하는 시퀀스
auto three_times_42 = std::views::repeat_n(42, 3);
for (int x : three_times_42) {
std::cout << x << ' '; // 출력: 42 42 42
}
return 0;
}
- 한 번의 호출로 n번 반복하는 유한 시퀀스 생성.
어떻게 좋아졌나요?
- 코드 간결성: 별도의 컨테이너 생성이나 사용자 정의 이터레이터 없이 단일 값 반복 시퀀스 생성 가능.
- 가독성 향상: repeat와 repeat_n이라는 직관적인 이름에서 의도가 명확히 드러남.
- 함수형 프로그래밍 스타일 강화: 다른 뷰(transform, filter, take, drop)와 결합해 복잡한 데이터 파이프라인을 단순화.
- 메모리 효율성: 값 하나를 반복하므로, 큰 메모리 비용 없이 게으른 평가로 시퀀스를 표현 가능.
다른 뷰와의 조합 예시
#include <ranges>
#include <iostream>
int main() {
// "Hello" 문자열을 5번 반복 후, 모두 대문자로 변환
auto repeated_hello = std::views::repeat_n("Hello", 5)
| std::views::transform([](auto s) {
std::string upper;
for (char c : std::string(s)) {
upper.push_back(static_cast<char>(std::toupper(static_cast<unsigned char>(c))));
}
return upper;
});
for (auto str : repeated_hello) {
std::cout << str << '\n';
}
// 출력:
// HELLO
// HELLO
// HELLO
// HELLO
// HELLO
return 0;
}
- repeat_n과 transform을 결합해 반복된 문자열 변환 처리도 간단히 표현.
주의 사항
- 무한 시퀀스 주의: repeat는 무한 시퀀스를 생성하므로, take나 drop 등을 사용해 제한하지 않으면 무한 루프 가능.
- C++23 지원 여부: C++23 기능이므로, 해당 기능 지원 컴파일러 및 표준 라이브러리 필요.
요약
C++23의 std::views::repeat와 std::views::repeat_n은 단일 값을 무한히 또는 지정 횟수만큼 반복하는 시퀀스를 손쉽게 생성하는 뷰 어댑터입니다. 이를 통해 테스트용 데이터 생성, 패턴 반복, 파이프라인과 결합한 데이터 변환 등 다양한 시나리오를 가독성 높게 구현할 수 있으며, 메모리 효율적이고 함수형 프로그래밍 스타일에 어울리는 코드를 작성할 수 있습니다.
참고 자료:
'개발 이야기 > C++' 카테고리의 다른 글
[C++23 새기능 소개] std::ranges::sample (0) | 2024.12.12 |
---|---|
[C++23 새기능 소개] std::in_place_stop_source와 std::in_place_stop_token (0) | 2024.12.12 |
[C++23 새기능 소개] std::views::common (0) | 2024.12.12 |
[C++23 새기능 소개] std::ranges::drop_last, std::ranges::drop_last_while (1) | 2024.12.12 |
[C++23 새기능 소개] std::byteswap (0) | 2024.12.12 |