본문 바로가기
개발/C++ (98,03,11,14,17,20,23)

Modern C++ : template, std::span (20)

by snowoods 2025. 8. 20.

Modern C++

C++ 템플릿과 std::span을 활용한 컨테이너 순회

 

개요

C++ 템플릿은 다양한 데이터 타입에 대해 동작하는 일반화된 코드를 작성할 수 있게 해주는 강력한 기능입니다. std::span은 C++20에서 도입된 뷰(view) 타입으로, 연속된 메모리 영역을 안전하고 편리하게 다룰 수 있게 해줍니다. 이 두 기능을 조합하면 다양한 컨테이너 타입을 일관된 방식으로 처리할 수 있는 유연한 코드를 작성할 수 있습니다.

 

C++ 버전별 주요 키워드 도입 시기

  • C++98/03: 기본 템플릿 지원 시작
  • C++11: auto, 범위 기반 for 루프, std::array 도입
  • C++14: 일반화된 람다 캡처, 변수 템플릿
  • C++17: 클래스 템플릿 인수 추론(CTAD), std::string_view
  • C++20: std::span, 개념(Concepts), 제약 조건 템플릿

 

내용 설명

템플릿 기본 구문

template <typename T>
void function_name(T parameter) {
    // 함수 본문
}
  • template <typename T>: T라는 이름의 템플릿 매개변수를 선언
  • T는 컴파일 시점에 실제 타입으로 대체됨
  • typename 대신 class 키워드도 사용 가능 (의미상 동일)

 

std::span

  • 연속된 메모리 시퀀스의 뷰를 제공하는 클래스 템플릿
  • 컨테이너의 데이터를 복사하지 않고 참조만 유지 (소유권 없음)
  • std::vector, 배열, std::array 등 연속 메모리 컨테이너와 호환
  • 크기 정보를 함께 전달하므로 배열 붕괴(decay) 문제 방지

 

예제 코드

#include <array>
#include <cstdint>
#include <iostream>
#include <span>
#include <vector>

// 템플릿 함수: 모든 연속 컨테이너를 받아 요소 출력
template <typename T>
void print_container(std::span<T> span)
{
    std::cout << "Container elements (size: " << span.size() << "):\n";
    for (const auto& val : span)
    {
        std::cout << val << ' ';
    }
    std::cout << "\n\n";
}

int main()
{
    // 다양한 타입의 컨테이너들
    auto my_vec = std::vector<std::int32_t>{1, 2, 3, 4, 5};
    auto my_arr = std::array<std::uint16_t, 5U>{1, 2, 3, 4, 5};
    std::uint64_t my_c_arr[] = {1, 2, 3, 4, 5};

    // 템플릿 함수 호출 (타입 명시적 지정)
    print_container<std::int32_t>(my_vec);
    print_container<std::uint16_t>(my_arr);
    print_container<std::uint64_t>(my_c_arr);

    // C++17부터는 템플릿 인자 추론으로 타입 생략 가능
    print_container<int>({my_vec.data(), 3});  // 처음 3개 요소만 출력

    return 0;
}

 

실행 결과

Container elements (size: 5):
1 2 3 4 5 

Container elements (size: 5):
1 2 3 4 5 

Container elements (size: 5):
1 2 3 4 5 

Container elements (size: 3):
1 2 3 

 

활용팁

  1. 성능 최적화: std::span은 데이터를 복사하지 않으므로 대용량 데이터 처리 시 성능 이점이 있습니다.
  2. 타입 안전성: C 스타일 배열보다 안전하며, 크기 정보를 함께 전달할 수 있습니다.
  3. 제네릭 프로그래밍: 다양한 컨테이너 타입을 하나의 템플릿 함수로 처리할 수 있습니다.
  4. 인터페이스 단순화: 함수 매개변수로 포인터와 크기를 따로 전달할 필요가 없어집니다.
  5. 주의사항: std::span은 참조만 유지하므로, 원본 데이터의 수명이 span보다 길어야 합니다.
  6. C++20 이상 필요: 프로젝트에서 C++20 이상을 지원해야 사용 가능합니다.
  7. 컴파일러 지원: 최신 버전의 GCC(10+), Clang(10+), MSVC(2019 16.7+)에서 완전히 지원됩니다.