Modern C++ 기능이란 C++17/20/23에서 도입된 ranges, concepts, modules 등 성능·표현력에 영향을 주는 기능을 말합니다. 본 챕터에서는 이들의 비용과 이점을 정리하고, Low-latency 코드에서 활용할 때 측정·기준을 다룹니다.
이 장을 읽기 전에
완전한 초보자? 이 장은 08장: 템플릿/constexpr의 컴파일 타임 개념을 전제로 합니다. C++17/20/23이라는 표준 버전 구분과 ranges·concepts가 “표현력을 위한 기능"이라는 정도만 알면 충분합니다.
이 장의 깊이: 이 장은 중급–전문가를 포괄합니다. ranges·concepts·modules의 성능 특성을 정리하는 것부터 시작해, 전문가 구간에서는 ranges 파이프라인이 인라인되는지, concepts가 런타임 비용 없이 제약만 거는지 등 “표현력 vs 런타임 비용"을 구분하는 기준을 다룹니다. 다루지 않는 것: 모듈의 빌드 시스템 통합 세부(Tr.03 컴파일러 트랙)와 코루틴(10장)입니다.
당신의 수준에 맞는 경로
| 수준 | 읽을 부분 | 핵심 목표 |
|---|---|---|
| 초보자 | “Ranges (C++20)” ~ “Concepts (C++20)” | 기능의 목적과 런타임 비용 유무 이해 |
| 중급자 | “Modules (C++20)” ~ “기타 C++17/20/23 기능 (성능 관점)” | 핫패스에 쓸지 측정으로 판단 |
| 전문가 | “판단 기준” ~ “비판적 시각” | 표현력과 성능의 트레이드오프 선택 |
C++17/20/23 성능 관련 기능 (역사·배경)
Ranges는 C++20에서 표준에 들어왔고, 범위 기반 연산과 뷰·지연 평가를 제공합니다. Concepts도 C++20에서 도입되어 템플릿 제약을 타입 시스템으로 표현합니다. Modules는 C++20에서 표준화되어 헤더 대신 모듈 단위로 인터페이스를 나누어 컴파일 시간과 노출 범위를 줄입니다. 각 기능은 “표현력·안전성·빌드"에 이점이 있으나, Low-latency에서는 런타임 오버헤드가 있는지(예: ranges 파이프라인 인라인, concepts의 런타임 비용 없음)를 구분해 핫패스에 쓸지 결정해야 합니다.
“A range is a sequence of elements that can be iterated. A view is a non-owning range that is O(1) to copy and move.” — cppreference: Ranges library. 뷰는 복사가 저렴하고 지연 평가되므로, 파이프라인으로 연결해도 중간 컨테이너 할당을 줄일 수 있습니다.
Ranges (C++20)
Ranges 라이브러리는 범위(range)를 인자로 두고, 뷰(view)를 파이프 |로 연결해 연산을 표현합니다. 많은 뷰는 지연 평가되어 최종적으로 소비(순회·수집)될 때만 연산이 실행됩니다. 뷰는 대체로 복사 없이 원본 범위를 참조하므로 중간 컨테이너 할당을 줄일 수 있습니다.
뷰를 파이프 |로 연결하면 중간 결과 없이 최종 소비 시점에만 연산이 실행됩니다.
| |
ranges vs 수동 루프: 위 파이프라인은 다음 for 루프와 동일한 결과를 냅니다.
| |
선언적 파이프라인은 가독성이 좋지만, 구현체·최적화 수준에 따라 어댑터 객체와 반복자 래핑이 충분히 인라인되지 않으면 µs 경로에서 오버헤드가 보일 수 있습니다. 핫패스에서는 두 버전을 같은 알고리즘으로 벤치마크해 오버헤드가 허용 범위인지 확인한 뒤 사용하는 것이 안전합니다.
Concepts (C++20)
Concepts는 템플릿 파라미터에 제약을 걸어, 컴파일 타임에 타입이 요구사항을 만족하는지 검사합니다. 에러 메시지가 명확해지고 오버로드 해석이 더 잘 짜이며, 만족하는 타입에 대해서는 기존 템플릿과 동일하게 인라인·최적화되어 추가 런타임 오버헤드가 없습니다.
아래는 template<std::integral T> 단축 표기와 requires 절을 함께 보여 줍니다.
| |
성능 트랙에서는 “concepts는 컴파일 타임 제약일 뿐 런타임 비용이 없다"는 점을 인지하고, 표현력·검사용으로 활용합니다.
Modules (C++20)
Modules는 번역 단위 단위로 인터페이스와 구현을 나누어, 헤더를 반복 파싱하지 않고 컴파일 시간을 줄이고 빌드 캐시를 활용할 수 있게 합니다. 모듈에서 export한 선언만 보이므로 노출 범위가 작아져 인라인·최적화 경계가 더 예측 가능해질 수 있습니다.
| |
사용하는 쪽은 이 인터페이스 단위를 헤더처럼 #include하는 대신 import합니다. 컴파일러는 math.ixx를 파싱하지 않고 이미 만들어진 모듈 메타데이터만 읽으므로, 헤더를 매 TU마다 재파싱하는 비용이 사라집니다.
| |
다만 아직 구현체·빌드 시스템·도구 지원이 플랫폼마다 다르므로(모듈 인터페이스 확장자·빌드 플래그가 컴파일러마다 상이함), 도입 시 빌드 설정과 성능을 프로젝트에서 측정해 보는 것이 좋습니다.
기타 C++17/20/23 기능 (성능 관점)
- if constexpr: 컴파일 타임에 분기가 결정되므로 선택되지 않은 경로의 코드는 생성되지 않고 런타임 분기도 없습니다. 템플릿 안에서 타입·상수에 따라 다른 구현을 택할 때 유용합니다(챕터 08 참고).
- 구조화된 바인딩: 튜플·구조체 멤버를 바인딩할 때 복사/참조를 명시할 수 있어 불필요한 복사를 줄이기 쉽습니다.
- [[likely]] / [[unlikely]]: 분기 예측 힌트로, CPU가 해당 경로를 선호하도록 할 수 있습니다. 효과는 플랫폼·컴파일러에 따라 다르므로 중요한 경로에만 쓰고 벤치마크로 확인합니다.
- std::format, constexpr 확장: 포맷·문자열 처리와 constexpr 가능 범위가 넓어져, 상수 문자열 생성·포맷을 컴파일 타임에 처리할 수 있는 경우가 늘었습니다.
평가 기준 (학습 성과 목표)
- Ranges의 지연 평가·뷰(non-owning) 특성을 설명하고, 핫패스에서 벤치마크 후 오버헤드가 허용되는지 판단할 수 있다.
- Concepts가 런타임 오버헤드 없이 컴파일 타임 제약만 추가함을 설명하고,
template<std::integral T>·requires절을 작성할 수 있다. - Modules가 컴파일 시간·노출 범위에 미치는 영향을 설명하고, 도입 시 빌드·성능을 측정할 수 있다.
- if constexpr, 구조화된 바인딩, [[likely]]/[[unlikely]] 등이 성능에 미치는 맥락을 구분할 수 있다.
판단 기준 (언제 쓰고 언제 피할지)
| 상황 | 권장 | 비권장 |
|---|---|---|
| ranges 파이프라인 | 벤치마크 후 오버헤드 허용 시 | µs 경로에 무검증 도입 |
| 템플릿 제약 | concepts로 가독성·에러 메시지 개선 | 런타임 비용 기대 (없음) |
| 빌드 시간·모듈화 | modules 실험·측정 후 도입 | 도구 미지원 환경에서 강제 |
자주 하는 실수
- ranges를 핫패스에 무검증 도입: 벤치마크 후 오버헤드가 허용될 때만 도입합니다.
- concepts에 런타임 비용 기대: concepts는 컴파일 타임만; 런타임 비용 없음.
- modules를 도구 미지원 환경에서 강제: 지원 여부와 빌드 시간 이득을 먼저 확인합니다.
리팩토링 시 주의
기존 for 루프를 ranges로 바꿀 때 동일 알고리즘인지 확인하고, 벤치마크로 회귀가 없는지 검증합니다. modules 도입 시 include 순서·헤더 노출이 바뀌므로 빌드·테스트를 충분히 수행합니다.
흔한 오해
“ranges는 항상 for 루프보다 느리다”(또는 그 반대로 “항상 같다”)는 둘 다 성급한 단정입니다. 어댑터가 충분히 인라인되면 수동 루프와 동등한 코드가 나오는 구현체도 있지만, 인라인이 안 되면 반복자 래핑 비용이 그대로 남습니다. “구현체·최적화 수준에 따라 다르다"가 정확한 답이며, 핫패스에 넣기 전에는 반드시 같은 알고리즘으로 벤치마크해야 합니다.
“concepts를 쓰면 실행 속도가 빨라진다”도 흔한 오해입니다. concepts는 컴파일 타임 제약일 뿐이며, 제약을 만족하는 타입에 대해서는 concepts가 없을 때의 일반 템플릿과 동일한 코드가 생성됩니다. concepts가 주는 이득은 런타임 속도가 아니라 컴파일 타임 오류 메시지와 오버로드 해석의 명확성입니다.
비판적 시각: 한계와 트레이드오프
- Ranges: 구현체·최적화에 따라 파이프라인 오버헤드가 있을 수 있다. “무조건 for 루프"가 아니라, 가독성과 성능을 벤치마크로 맞보는 것이 합리적이다.
- Modules: 빌드 시스템·컴파일러 지원이 아직 불균일하므로, 프로젝트별로 도입 가능 여부와 이득을 평가해야 한다.
핵심 요약
| 항목 | 요약 |
|---|---|
| Ranges | 지연 평가·뷰, 중간 할당 감소; 핫패스는 벤치마크 후 사용 |
| Concepts | 컴파일 타임 제약, 런타임 오버헤드 없음 |
| Modules | 컴파일 시간·노출 감소, 도구 지원 확인 필요 |
| 기타 | if constexpr·구조화 바인딩·[[likely]] 등 상황별 활용 |
용어 정리
| 용어 | 설명 |
|---|---|
| range | 순회 가능한 요소 시퀀스; C++20 std::ranges |
| view | non-owning, 복사 O(1), 지연 평가되는 range |
| concept | 템플릿 파라미터 제약; 컴파일 타임 검사, 런타임 비용 없음 |
| module | 헤더 대체; export한 선언만 노출, 빌드 시간·노출 감소 |
자주 묻는 질문 (FAQ)
Q: ranges가 항상 for 루프보다 느리나요?
A: 구현체·최적화에 따라 다릅니다. 동일 알고리즘으로 벤치마크한 뒤, 허용 가능한 오버헤드일 때만 핫패스에 도입합니다.
Q: concepts는 런타임 비용이 있나요?
A: 없습니다. 컴파일 타임 제약만 추가되므로, 가독성·에러 메시지 개선용으로 사용합니다.
Q: modules를 지금 도입해야 하나요?
A: 빌드 시스템·컴파일러 지원이 프로젝트마다 다릅니다. 실험·측정 후 도입 가능 여부를 평가합니다.
적용 체크리스트 (실무용)
- 핫패스에 ranges를 넣기 전 동일 알고리즘으로 벤치마크했는가?
- concepts는 런타임 비용 없음을 인지하고 가독성·에러 메시지용으로 썼는가?
- modules 도입 시 도구 지원·빌드 시간을 확인했는가?
- [[likely]]/[[unlikely]]는 효과를 측정한 뒤 적용했는가?
- 변경 후 벤치마크·빌드 시간으로 회귀 검증했는가?
추가 읽기 및 관련 챕터
- 챕터 08 (템플릿/constexpr): 컴파일 타임 전략과 연계.
- 챕터 10 (코루틴): C++20 비동기 기능.
- 챕터 14 (span과 뷰): 뷰 패턴·non-owning.
- cppreference: Ranges library — 뷰(view)·어댑터·지연 평가 모델을 정의하는 1차 출처.
- cppreference: Constraints and concepts — concepts·requires 절의 문법과 제약 해석 규칙을 다루는 1차 출처.
- cppreference: Modules — 모듈 인터페이스/구현 단위,
export/import의미론을 다루는 1차 출처.
C++26 전망 (짧은 갱신 노트)
이 장은 C++17/20/23 범위를 다루지만, C++26이 2026-03-29 런던 회의에서 최종 확정됐다는 사실은 짚고 넘어갈 가치가 있습니다. 성능과 직접 관련된 확정 기능으로는 정적 리플렉션(P2996)과 Contracts([[pre:]]/[[post:]])가 있으며, 둘 다 GCC 16.1(2026-04)에서 구현이 시작됐고 Clang은 아직 실험 포크 수준입니다. 즉 “예정된 기능"이 아니라 “확정된 표준, 구현은 초기 단계"로 이해하는 것이 정확합니다. 이 두 기능이 컴파일 타임 코드 생성·검증 비용에 미치는 영향은 컴파일러 지원이 성숙한 뒤 별도로 다룰 만한 주제입니다.
다음 장에서는
이전 장: 템플릿/constexpr (챕터 08)
코루틴 성능을 다룹니다. C++20 코루틴의 suspend/resume 비용, 프레임 할당, 저지연 경로에서의 활용 기준을 정리합니다. → 코루틴 성능 (챕터 10)
![Featured image of post [Optimization(C++) 09] Modern C++ 기능](/post/cpp-optimization/modern-cpp-features/wordcloud_hu_95806e2010771378.webp)
![[Optimization(C++) 07] 임시 객체 제거](/post/cpp-optimization/temporary-removal/wordcloud_hu_f763a659505ec6fc.webp)
![[Optimization(C++) 08] 템플릿/constexpr](/post/cpp-optimization/templates-constexpr/wordcloud_hu_652387c722476f19.webp)
![[Optimization(C++) 09] Modern C++ 기능](/post/cpp-optimization/modern-cpp-features/wordcloud_hu_82b9f8d4f98733a.webp)
![[Optimization(C++) 10] 코루틴 성능](/post/cpp-optimization/coroutine-performance/wordcloud_hu_57d450707cfb1c79.webp)
![[Optimization(C++) 11] 예외 처리 심화](/post/cpp-optimization/exception-deep-dive/wordcloud_hu_c542384a35b5a871.webp)
![[Optimization(C++) 13] std::variant/optional/expected](/post/cpp-optimization/variant-optional-expected/wordcloud_hu_b06d8ae673ab76c5.webp)
![[Optimization(C++) 16] Small Buffer Optimization](/post/cpp-optimization/small-buffer-optimization/wordcloud_hu_9326fd48e244893f.webp)
![[Optimization(C++) 17] Parameter Passing 전략](/post/cpp-optimization/parameter-passing/wordcloud_hu_a07c02ecf5f0707a.webp)
![[Optimization(C++) 19] Type Erasure 비용 패턴](/post/cpp-optimization/type-erasure-cost-patterns/wordcloud_hu_674b015a115a8d71.webp)
![[Optimization(C++) 03] 추상화 비용 분석](/post/cpp-optimization/abstraction-cost/wordcloud_hu_bdf31f65df6236b7.webp)