서의 공간

C++ 템플릿 본문

C++/Syntax, Features

C++ 템플릿

홍서의 2020. 11. 27. 07:20

템플릿 (C++) | Microsoft Docs

 

C++는 객체지향 프로그래밍 언어일 뿐만 아니라 제네릭 프로그래밍(generic programming) 언어이기도 하다. 제네릭 프로그래밍의 목적은 재사용 가능한 코드를 만드는 것이다. 이것을 위한 가장 기본적인 도구가 바로 템플릿(template)이다.

 

템플릿은 데이터 타입을 값으로 파라미터화 한다. C++에서 기본 내장 타입 int와 double은 물론 MyObject, Pawn 같은 사용자 정의 클래스까지 포함한다. 템플릿을 이용하면 값에 독립적일 뿐만 아니라 그 값의 타입에도 독립적인 코드를 만들 수 있다.

 

컴파일러가 템플릿 클래스를 처리하는 방법

컴파일러가 템플릿 메서드 정의 코드를 만나면 문법은 검사하지만 실제로 컴파일은 하지 않는다. 어떤 타입이 사용될지 알 수 없기 때문에 템플릿 정의 구문 자체는 컴파일할 방법이 없다. 즉, x = y와 같은 코드에서 x와 y의 타입을 모르는 것과 같다. 타입에 대한 정의 없이는 어떤 코드도 생성해낼 수 없다.

컴파일러가 Grid<int> myIntGrid 같은 템플릿 인스턴스화 코드를 만나면 템플릿 정의에서 T 부분을 int로 바꾼 새로운 클래스 정의 코드를 생성해낸다. 만약 Grid<SpreadsheetCell> mySpreadsheet 같은 또 다른 템플릿 인스턴스화 코드를 만나면 또다시 T를 SpreadsheetCell로 바꾼 새로운 클래스 정의 코드를 생성한다.

 

타입이 아닌 템플릿 파라미터

타입이 아닌(non-타입) 템플릿 파라미터는 int나 포인터 값 같이 일반적으로 함수나 메서드에서 사용할 수 있는 것들을 말한다. 하지만 non-타입 템플릿 파라미터에는 정수 타입 값(char, int, long 등), 열거 타입 값, 포인터 값, 참조형 변수 같은 것들만 가능하다.

아래 Grid 템플릿 클래스 예에서 Grid의 너비나 높이를 생성자 인자로 받지 않고 템플릿 인자로 받을 수도 있다. 생성자 인자 대신 템플릿 인자를 사용하면 컴파일 타임에 크기 값이 알려지기 때문에 최적하게 좀 더 유리한 장점이 있다. 템플릿 메서드는 컴파일 전에 템플릿 파라미터를 지정된 값으로 바꿔 넣기 때문에 동적 할당 대신 일반적인 정적 이차원 배열을 사용할 수 있다.

template <typename T, size_t WIDTH, size_t HEIGHT>
class Grid
{
public:
	Grid();
    virtual ~Grid();
    
    /* ...생략... */

private:
	T mCells[WIDTH][HEIGHT];
};

 

템플릿 특수화

특정 경우에 한해서 특별한 템플릿 정의가 사용되도록 하는 것을 템플릿 특수화라고 한다. 다음은 예제이다.

// partial_specialization_of_class_templates.cpp
template <class T> struct PTS {
   enum {
      IsPointer = 0,
      IsPointerToDataMember = 0
   };
};

template <class T> struct PTS<T*> {
   enum {
      IsPointer = 1,
      IsPointerToDataMember = 0
   };
};

template <class T, class U> struct PTS<T U::*> {
   enum {
      IsPointer = 0,
      IsPointerToDataMember = 1
   };
};

struct S{};

extern "C" int printf_s(const char*,...);

int main() {
   printf_s("PTS<S>::IsPointer == %d PTS<S>::IsPointerToDataMember == %d\n",
           PTS<S>::IsPointer, PTS<S>:: IsPointerToDataMember);
   printf_s("PTS<S*>::IsPointer == %d PTS<S*>::IsPointerToDataMember ==%d\n"
           , PTS<S*>::IsPointer, PTS<S*>:: IsPointerToDataMember);
   printf_s("PTS<int S::*>::IsPointer == %d PTS"
           "<int S::*>::IsPointerToDataMember == %d\n",
           PTS<int S::*>::IsPointer, PTS<int S::*>::
           IsPointerToDataMember);
}
// OUTPUT
PTS<S>::IsPointer == 0 PTS<S>::IsPointerToDataMember == 0
PTS<S*>::IsPointer == 1 PTS<S*>::IsPointerToDataMember ==0
PTS<int S::*>::IsPointer == 0 PTS<int S::*>::IsPointerToDataMember == 1

 

'C++ > Syntax, Features' 카테고리의 다른 글

C++ 복사 생성자와 임시 객체  (0) 2020.12.13
C++ 키워드  (0) 2020.11.27
C++ STL(Standard Template Library)  (0) 2020.11.27
C++ Standard Library (표준 라이브러리)  (0) 2020.11.27
Comments