[C++] 함수에 std::vector 전달하기

반응형

std::vector를 매개변수로 하는 함수

std::vector는 다양한 타입의 데이터를 담을 수 있는 컨테이너입니다.

이 컨테이너는 사용자가 원한다면, 매우 많은 원소를 저장할 수 있기 때문에, 함수에서 사용하려면 값에 의한 전달( call by value )이 아니라 참조에 의한 전달( call by reference ) 방식을 사용해야 합니다.

#include <iostream>
#include <vector>

// vector를 매개변수로 하는 함수
void printData( const std::vector<int>& vec){    

    for( auto i : vec){
        std::cout << i << " ";
    }
    std::cout << '\n';
}

int main(){

    std::vector<int> vec{ 1, 2, 3, 4, 5 };
    printData( vec );
}

▼출력

1 2 3 4 5

그런데, 다양한 타입을 저장할 수 있는 템플릿 클래스의 객체를 매개변수로 사용하면서, 함수 자체는 고정된 타입의 인자만을 수용할 수 있도록 작성하는 것은 스스로 코드의 가능성을 제한하는 일이 될 것입니다.

 

그러므로 위와 같이, 템플릿을 사용하는 타입을 매개변수로 가진 함수는 템플릿 함수로 구현해야 합니다.

그리고, 이렇게 하는 데는 두 가지 방법이 있습니다.

 

vector의 데이터 타입을 지정하는 함수 템플릿

이 방식은 함수 템플릿 매개변수( template parameter ) Tstd::vector가 저장하는 데이터 타입을 지정하는 함수 템플릿을 작성하는 것입니다.

template <typename T >
void printData( const std::vector<T>& vec){    

    for( auto x : vec){
        std::cout << x << " ";
    }
    std::cout << '\n';
}

int main(){

    std::vector<int> vec{ 1, 2, 3, 4, 5 };
    printData( vec );

    std::vector<double> vec2{ 1.1, 2.2, 3.3, 4.4 };
    printData( vec2);
}

▼출력

1 2 3 4 5 
1.1 2.2 3.3 4.4

하나의 함수 템플릿을 통해서, intdouble 타입의 데이터들을 동일한 방식으로 처리할 수 있게 되었습니다.

 

만약, 특정한 데이터 타입에 대해서, 다른 타입과 다른 기능을 수행하는 함수를 작성하고 싶다면, 위 함수 템플릿의 특수화( template specialization )된 함수를 구현할 수도 있습니다.

template<>  // 함수 템플릿의 특수화
void printData( const std::vector<double>& vec){
    
    // double 데이터를 과학적 표기법으로 표시
    std::cout << std::scientific;	

    for( auto x : vec){
        std::cout << x << " ";
    }
    std::cout << '\n';
}

▼출력

1 2 3 4 5
1.100000e+00 2.200000e+00 3.300000e+00 4.400000e+00

이 특수화된 템플릿 함수는, 기본 템플릿에서 인스턴스화된 함수가 있더라도 컴파일러에 의해 우선적으로 선택되고 사용됩니다.

 

다양한 타입의 매개변수를 사용할 수 있는 함수 템플릿

이 방식은 위의 방식보다 더 범용적인 타입을 매개변수로 사용할 수 있도록 하는 함수 템플릿입니다.

template <typename T >	// 다양한 타입의 매개변수가 가능한 함수 템플릿
void printData( const T& vec){    

    for( auto x : vec){
        std::cout << x << " ";
    }
    std::cout << '\n';
}

이 방식의 장점은 인자가 std::vector 타입이 아니어도, 이 함수 템플릿을 이용할 수 있다는 것입니다.

특히, std::arraystd::string 같이 사용법이 유사한 템플릿 클래스 타입을 인자로 전달할 수 있다는 강점이 있습니다.

#include <iostream>
#include <vector>
#include <array>

int main(){

    std::vector<int> vec{ 1, 2, 3, 4, 5 };
    printData( vec );

    std::vector<double> vec2{ 1.1, 2.2, 3.3, 4.4 };
    printData( vec2);

    std::array<int, 5 > arr{ 1, 2, 3, 4, 5};	// 배열도 함수 템플릿을 이용
    printData( arr);

    std::string str{ "This is a string"};
    printData( str);
}

▼출력

1 2 3 4 5 
1.1 2.2 3.3 4.4
1 2 3 4 5
T h i s   i s   a   s t r i n g

하지만, std::vector 클래스만이 가진 기능( 예를 들면, emplace, emplace_back )을 이용한 코드는 작성할 수 없습니다. 

 

 

정리

  • 템플릿을 사용하는 타입을 매개변수로 하는 함수를 작성할 때는, 함수 템플릿( function template )을 우선적으로 고려하는 것이 타당합니다.

 

 

 

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유