HOWTO · C++

C++에서 STL 컨테이너의 value_type

STL은 Standard Template Library의 약자입니다. C++ 프로그래밍 언어용 일반 컨테이너 및 함수를 구현하는 데 사용되는 데이터 구조 및 알고리즘 집합입니다.

이 페이지의 내용

STL 컨테이너의 value_type은 컨테이너가 저장하는 원소의 타입을 가리키는 타입 별칭입니다. std::vector<int>에서는 그 타입이 int이고, std::map<std::string, int> 같은 연관 컨테이너에서는 키와 값으로 이루어진 쌍입니다. 컨테이너 타입을 통해 이 별칭을 지정할 수 있으며, 컨테이너 타입이 템플릿 매개변수인 제네릭 코드에서도 사용할 수 있습니다.

value_type의 의미

컨테이너는 원소 각각의 타입을 나타내는 value_type을 정의합니다. 예를 들어 std::vector<int>::value_type은 int이고, 맵의 원소 타입은 키와 매핑된 값으로 이루어진 쌍입니다. std::map<std::string, int>에서 원소는 첫 번째 멤버가 키이고 두 번째 멤버가 그 키에 연결된 값인 std::pair입니다. 저장된 쌍에서 키는 정렬이 올바르게 유지되도록 const입니다. 이 별칭을 사용하면 컨테이너를 다루는 코드에서 원소 타입을 별도로 적지 않고도 참조할 수 있습니다. value_type은 컨테이너 객체 자체가 아니라 저장된 원소 하나의 타입을 나타냅니다. 정수를 담는 벡터의 원소 타입은 int이며, 벡터는 이와 별개의 컨테이너 타입입니다.

컨테이너의 value_type에 접근하기

범위 지정 연산자 앞에 컨테이너의 타입을 씁니다. 예를 들면 std::vector<int>::value_type입니다. 이는 타입 이름이므로 myVector가 객체라면 myVector::value_type은 올바른 표현이 아닙니다. 원소 타입에 다른 이름을 붙이고 싶다면 using Element = std::vector<int>::value_type;이라고 작성할 수 있습니다. Container가 템플릿 매개변수일 때도 Container::value_type이라는 표현을 사용합니다. 이 이름은 종속 타입 이름이므로 C++에서는 앞에 typename을 붙여야 합니다. 템플릿 선언만으로는 종속 이름이 타입을 가리키는지 값인지 컴파일러가 알 수 없으므로, typename으로 타입이라는 점을 명시합니다. std::vector<int>::value_type처럼 컨테이너 타입이 이미 구체적으로 정해진 일반 코드에서는 컴파일러가 중첩 타입을 바로 확인할 수 있어 이런 구분 표시가 필요하지 않습니다.

제네릭 코드에서 value_type 사용하기

제네릭 함수는 서로 다른 컨테이너를 인수로 받으면서 typename Container::value_type을 사용해 원소 타입을 지정할 수 있습니다. 다음 예제는 벡터와 리스트의 각 원소를 출력합니다. 출력에 표시되는 색상 레이블 red와 blue는 영어로 그대로 표시됩니다.

예제를 실행해 보세요.

#include <iostream>
#include <list>
#include <string>
#include <vector>

template <typename Container>
void printElements(const Container& container) {
    for (const typename Container::value_type& element : container) {
        std::cout << element << '\n';
    }
}

int main() {
    const std::vector<int> numbers{1, 2, 3};
    const std::list<std::string> colors{"red", "blue"};

    printElements(numbers);
    printElements(colors);
}

출력은 다음과 같습니다.

1
2
3
red
blue

함수에서 Container는 인수로부터 추론되므로, 같은 함수 본문이 std::vector<int>와 std::list<std::string> 모두에서 동작합니다. Container::value_type은 해당 템플릿 매개변수에 따라 달라지는 이름이므로 선언에 typename을 씁니다. 반복문은 각 원소를 const 참조로 받습니다. 따라서 원소를 복사하지 않고 읽을 수 있지만, 이 참조를 통해 컨테이너의 원소를 수정할 수는 없습니다. 이 방식은 특정 컨테이너 하나에 종속되지 않으면서 지역 변수, 매개변수 또는 반환 타입에 사용할 원소 타입을 지정해야 할 때 유용합니다. 다만 컨테이너는 함수가 사용하는 연산을 지원해야 합니다. 여기서는 범위 기반 반복이 두 컨테이너에 공통으로 필요한 기능입니다.

value_type이 하지 않는 일

value_type은 원소 타입을 가리킬 뿐, 메모리를 할당하거나 해제하지 않습니다. 저장 공간은 컨테이너와 해당 할당자가 각자의 규칙에 따라 관리합니다. 또한 이 별칭이 어떤 컨테이너를 다른 컨테이너보다 항상 빠르거나 안전하게 만들어 주는 것도 아닙니다. 여기서 실용적인 이점은 제네릭 코드가 사용자 정의 원소 타입을 포함해 각 컨테이너가 제공하는 원소 타입을 지정할 수 있다는 점입니다. value_type이 있다고 해서 모든 컨테이너의 인터페이스가 같아지는 것도 아닙니다. 코드는 인수로 받는 컨테이너가 지원하는 연산에만 의존해야 합니다. 필요한 연산과 성능 특성에 맞춰 컨테이너를 선택하고, 원소 타입이 그 선택에 따라 달라져야 할 때 해당 컨테이너의 별칭을 사용하세요. 요약하면 value_type은 제네릭 코드에 원소의 타입을 알려 주지만, 컨테이너가 원소를 저장하거나 관리하는 방식까지 정하지는 않습니다.