[Basic C++] #55_템플릿
C++의 템플릿 중 "템플릿"에 대해 알아보겠습니다.
"전문가를 위한 C"의 11 항목, "템플릿을 이용한 제네릭 코드 작성"에 해당하는 내용입니다.
템플릿
"템플릿"은 제네릭 프로그래밍의 좋은 예시입니다.
먼저, 제네릭 프로그래밍이란 데이터 형식으로부터 독립적이며, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있는 프로그래밍 방식입니다.
템플릿은 데이터 타입이 "매개 변수"를 통해 표현되며, 우리는 데이터 타입의 파라미터화로 기억하면 되겠습니다!
1. 템플릿 선언
template<typename T>
템플릿 선언부 먼저 살펴봅시다!
앞서 말했듯이, 템플릿은 "데이터 타입"을 파라미터화합니다.
우리는 타입 파라미터를 "T"로 가정하며, "template"과 "typename" 키워드와 함께 <> 안에 작성합니다.
우리는 템플릿을 사용하기 위해 실제 사용할 데이터 타입을 템플릿의 인자로 넘겨줘야겠죠!
2. 템플릿 정의
myClass(const myClass<T>& src); // 복제 생성자
myClass<T> operator = (const myClass<T>& rhs); // 대입 연산자
템플릿 클래스를 예제로 "템플릿"의 실제 구현 부분을 살펴보겠습니다.
템플릿 클래스를 사용할 때는 클래스 이름을 "템플릿 이름"으로 염두하고 사용해야 합니다.
쉽게 말해, "myClass"를 실제 사용할 특정 데이터 타입으로 인스턴스화한 결과물로 지칭해야 합니다!
따라서, 우리는 "<T>"를 사용해 해당 타입이 추후에 지정될 것임을 명시해줘야 합니다!
3. 템플릿 클래스의 메서드 정의
template<typename T>
myClass<T>::myClass(size_t _Width, size_t _Height) : width(_Width), height(_Height)
{
// 생성자 정의...
}
템플릿 클래스의 멤버 함수를 정의할 때도 마찬가지로 "템플릿 선언부"를 먼저 작성해줍니다.
빨간색으로 하이라이트 된 부분들을 명심해야 합니다.
선언부와 함께 범위 지정 연산자를 "myClass<T>"로 작성함으로써 추후에 특정 데이터 타입으로 인스턴스화된 결과물로 지정해야 합니다!
4. 템플릿 활용
myClass<int> myClass1;
myClass<double> myClass2 (11, 11);
위 예제 코드는 미리 작성한 템플릿 클래스를 활용하는 방법입니다.
보시다시피, "<T>"에서 "T"에 들어갈 데이터 타입을 지정해주어 재사용성을 효과적으로 향상하죠!
"int"가 될 수 있으며, "double" 또한 문제없이 사용 가능합니다.
5. 컴파일러와 템플릿 코드
살짝 지루한 얘기지만, 컴파일러가 템플릿 코드를 어떻게 처리하는지 알아야 한다고 합니다...
컴파일러가 템플릿 메서드 정의 코드를 만나면 문법 검사만 실시하고, 실제 컴파일은 실행하지 않습니다.
반면에, 컴파일러는 "myClass<int>"와 같이 "템플릿 인스턴스화" 코드를 만나면 새로운 정의 코드를 생성하죠.
정리하자면, "인스턴스화"되지 않은 템플릿 코드는 컴파일되지 않습니다!
그러므로, "myClass<T>"와 같이 매번 템플릿 파라미터를 명시적으로 작성해야 하겠죠.
6. 파일 나누기
템플릿 클래스 정의부와 메서드 구현부를 파일 별로 나누는 방법들을 알아보겠습니다.
1. 템플릿 클래스 정의 + 템플릿 메서드 구현부 -> 1 개의 헤더 파일
첫 번째 방법은 (템플릿) 클래스 정의와 메서드 구현부를 하나의 헤더 파일에 모두 작성하는 방법입니다.
2. 템플릿 클래스 정의 -> 헤더 파일 1 + #include "헤더_파일2", 템플릿 메서드 구현부 -> 헤더_파일 2
두 번째 방법은 두 개를 서로 다른 헤더 파일에 작성하는 방법입니다.
템플릿 클래스 정의를 담고 있는 헤더 파일에서 템플릿 메서드 구현부를 담고 있는 헤더 파일을 "#include" 해줍니다.
3. 템플릿 클래스 정의 -> 헤더 파일 1 + #include "소스_파일1", 템플릿 메서드 구현부 -> 소스_파일1
마지막 방법은 클래스 정의를 담고 있는 헤더 파일에서 메서드 구현부를 담고 있는 소스 파일을 "#include" 하는 방법입니다.
헤더 파일에서 소스파일을 "#include"하는 것이 다소 어색하지만, C++에서 정식으로 허용한다고 합니다!
7. 템플릿 인스턴스화 대상 타입 제한
만약, 작성한 템플릿이 특정 타입에 대해서만 인스턴스화 되길 원한다면 우리는 아래와 같이 코드를 작성합니다!
1. 헤더 파일. h
// 템플릿 클래스 정의 부
template<typename T>
class myClass
{
//...
}
2. 소스파일. cpp
// 메서드 구현부
#include "myClass.h"
template<typename T>
myClass<T>::myClass(size_t inWidth, size_t inHeight) : width(inWidth), height(inHeight)
{
// 생성자 정의...
}
// .cpp 소스 파일의 마지막
template class myClass<int>;
template class myClass<double>;
template class myClass<vector<int>>;
먼저, 클래스를 정의한 헤더 파일에서 메서드 정의부를 작성한 소스 파일을(.cpp) "#include"하지 않고 있죠!
그리고, 소스 파일(.cpp)에서 인스턴스화 되길 원하는 특정 타입들을 선언하여 독립적으로 빌드와 링킹 되게 하면 다른 타입으로 인스턴스화 되는 것을 방지할 수 있습니다!
'언어 > Basic C++' 카테고리의 다른 글
[Basic C++] #55-3_템플릿 메서드, 이중 템플릿 (0) | 2022.07.27 |
---|---|
[Basic C++] #55-2_템플릿 파라미터 (0) | 2022.07.27 |
[Basic C++] #54_STL 작업 알고리즘, for_each() (0) | 2022.07.20 |
[Basic C++] #53_STL 알고리즘, remove + erase, 옮기고 삭제하기 (0) | 2022.07.19 |
[Basic C++] #52_STL 알고리즘, replace (0) | 2022.07.19 |