👩🏻‍💻기초지식/C++

[C++] 템플릿 (Template)

공대 컴린이 2023. 10. 31. 17:07
728x90

정의

템플릿은 C++ 프로그래밍 언어의 한 기능으로, 함수나 클래스를 일반화하여 여러 타입에 대해 동작하는 코드를 작성할 수 있는 도구입니다. 템플릿을 사용하면, 함수나 클래스가 개별적으로 다시 작성하지 않고도 각기 다른 수많은 자료형에서 동작할 수 있게 합니다.

 

템플릿의 종류로는 함수를 다양한 타입에 대해 동작하도록 일반화하는 '함수 템플릿'과, 클래스를 일반화하는 '클래스 템플릿'이 있으며, 연산자 오버로딩에서 자주 사용됩니다.

 

동작 원리

템플릿 코드를 작성하고 나서, 템플릿 함수나 클래스를 사용하면 컴파일러는 제공된 타입에 맞는 코드를 생성합니다. 이를 '템플릿 인스턴스'라고 합니다.

 

더 자세한 템플릿의 동작원리를 이해하려면 프로그램의 빌드 과정을 이해해야 합니다. 프로그램이 빌드되면 컴파일부터 링크과정을 거치는데, 템플릿은 컴파일 과정에서 결정됩니다.

보통, 컴파일 시에 컴파일러가 코드를 순차적으로 읽으며 진행하다가 함수의 선언부를 읽어서 함수의 존재를 인지하고, 함수를 사용하는 main 영역에서 함수를 확인합니다. 이후, 함수 구현부를 확인하며 메모리에 어떻게 올릴지 결정하고 링크 과정에서 함수의 선언부와 구현부를 연결시킵니다.

 

템플릿은 빌드과정 초기에 자료형이 정해져 있지 않기 때문에, 컴파일 과정에서 템플릿을 일단 무시하고 지나갑니다. 이후 컴파일을 계속 진행하다가 템플릿 함수와 같은 함수를 호출하는 시점을 찾으면 일단 자료형에 맞는 일반 함수를 찾고, 없다면 템플릿 함수를 참조합니다.

이후, 자료형이 같다면 해당 템플릿 함수를 호출한 함수의 자료형인 새로운 함수로 코드를 작성합니다. 즉, 템플릿 함수의 구현부를 프로그래머가 입력으로 전달한 자료형의 형식으로 만드는 것입니다.

 

오류 발생 예시

템플릿은 컴파일 시점에 타입을 결정하고 코드를 생성하기 때문에, 템플릿의 선언과 정의가 헤더 파일(.h, .hpp)에 모두 포함되어 있지 않다면 링크 에러가 발생합니다. 컴파일러가 헤더파일을 검사하면서 템플릿의 정의를 찾는데, cpp 파일에 정의가 있을 경우 정의를 찾을 수 없기 때문입니다.

이를 해결하기 위해선, 일반적으로 템플릿의 선언과 정의를 모두 헤더파일에 포함시키거나, 헤더파일과 cpp 파일이 합쳐진 .hpp 파일에 정의할 수 있습니다. 또는 헤더파일에 cpp 파일을 include 하면 오류는 나지 않습니다. (근데 그냥 헤더파일에 다 정의하는게..)

 

장점과 단점

템플릿은 코드의 재사용성을 높이고, 타입 안전성을 보장할 수 있습니다. 타입 안전성을 보장한다는 뜻은, 템플릿은 컴파일 시점에 타입을 확인하므로 잘못된 타입의 사용이 있을 때 컴파일 오류로 잡아낼 수 있기 때문입니다.

 

반면, 템플릿은 컴파일 시간을 증가시키며 복잡한 코드를 생성할 수 있으므로 적절히 사용해야 합니다.

자료형을 주어졌을 때 생성되는 각 템플릿 인스턴스는 별도의 코드를 생성하기 때문에, 많은 수의 템플릿 인스턴스를 사용하면 실행 파일의 크기가 커질 수 있습니다. 그리고 템플릿 코드는 컴파일러에 의해 생성되므로 컴파일 오류 메시지가 복잡하거나 이해하기 힘들어 디버깅이 어려울 수 있습니다.


템플릿 특수화

템플릿 특수화는 특정 타입에 대해 템플릿의 동작을 변경하고 싶을 때 사용하는 기법입니다. 기본 템플릿이 정의되고 난 후, 특정 타입이나 조건에 대해 템플릿의 행동을 재정의할 수 있습니다.

 

템플릿 특수화는 모든 매개변수에 대해 특정 타입을 지정하는 '전체 특수화'와, 일부 매개변수에 대해 특정 타입을 지정하는 '부분 특수화'가 있습니다. 단 부분 특수화는 클래스 템플릿에만 적용할 수 있습니다.

 

> 실행 결과

Specialized version for int: 5
General version: 5

 

위 코드에서 print(5)는 <int> 자료형으로 특수화 시켜놓은 print 함수가 호출되고, print(5.0)은 일반 템플릿 함수를 사용합니다.

 

std::vector<bool> 특수화

C++의 STL 중 하나인 vector의 자료형으로 bool 값을 넘겨주면, <bool> 템플릿 특수화 함수가 적용됩니다.

일반적으로 std::vector<T>는 T 타입의 동적 배열을 나타냅니다. 그러나 bool 타입을 넘겨주는 경우, 메모리 사용량을 줄이기 위해 각 bool 값을 1비트로 저장하는 함수들이 제공됩니다. 즉, 8개의 bool 값이 1바이트에 저장되어 메모리를 효율적으로 사용하기 위함입니다.

728x90