열혈 강의 12장 : 템플릿


template <typename T>

T Add(T a, T b){

return a+b;

}


쉽게 말해 자료형을 결정 짓지 않는 것.


1. 함수 템플릿

2. 템플릿 함수  --> 함수 템플릿에 의해 실제 호출이 가능한 함수.


template <typename T>

void show(T a, T b){

cout<<a<<'  '<<b<<endl;

}


int main(){

show(5, 5.5);   --> 컴파일 에러, 어느 장단에 맞춰야 할지 모른다.

}


======================= 해결책


template <typename T1 , tepename T2>

void show (T1 a, T2 b){ ... }   --> 두개의 템플릿을 선언해 준다.



2. 함수 템플릿의 특수화


template <typename T>

void SizeOf(T a){

cout<<sizeof(a)<<endl;

}


int main(){

int a = 10;

float f = 10f;

double d = 10.0;

char* name = "name";


SizeOf(a);                       /// 4

SizeOf(f);                        /// 4

SizeOf(d);                        /// 8

SizeOf(name);                 ///4 --------> 포인터의 크기가 출력된다. 함수 내에서 return strlen(name); 이 반환되기를 원할 것이다.

}


============================해결책


tempalte<typename T>

void SizeOf(T a) { ... }


template<>                             -------------> 특수화, 원래는 한줄에 같이 쓴다. template<> void SizeOf(char* _name) { ... }

void SizeOf(char* _name){

return strlen(_name);

}


--> template<> void SizeOf<char*> (char* _name){ ... }  --> 올바른 선언 방법



3. 클래스 템플릿


template<typename T>   --> 다음에 정의하는 클래스를 템플릿화 하겠다.

class Data{                       --> 클래스가 아니라 템플릿이다.

private:

T data;

public:

Data(T a) { data = a; }

T GetData(){ return data; }

void SetData(T a){ data = a; }

};


int main(){

Data<int> d1(0);

Data<char> d2('a');

}


----> 객체 생성 시 결정하고자 하는 자료형을 명시적으로 선언해 주어야 한다.

--> 객체 생성 순서 --> 메모리 할당 --> 생성자 호출

--> 메모리 공간의 할당이 우선적으로 진행되어야 하기 때문에 T의 자료형을 알고 있어야 한다.

--> 때문에 명시적으로 선언을 해주어야 한다.


선언과 정의 분리


template<typename T>

Data<T>:: Data(T a) { data = a; }


template<typename T>

T Data<T>:: GetData() { return data; }


teplate <typename T>

void Data<T>:: SetData(T a) { data = a; }


--> 멤버 함수를 정의할 때마다 반드시 붙여 줘야 한다.

--> Data<T> --> 클래스 Data가 아닌 클래스 템플릿 Data를 의미한다.


4. 스택 클래스의 템플릿화


template <typenaem T> 

class Stack{

private:

int len;

T* data;

public:

Stack() : len (-1) { data = new T[100]; }

void push(T a);

T pop();

}


template <typename T>

void Stack<T>:: push(T a){ data[++len] = a; }

tempalte <typename T>

T Stack<T>:: pop() { return data[len--]; }



int main(){

Stack<int> a;

a.push(10);

a.push(20);


Stack<char> c;

c.push('a');

c.push('b');

}



5. 템플릿의 원리 이해

--> 템플릿 함수의 인스턴스화

--> 템플릿 클래스의 인스턴스화


template<typename T>

T Add(T a, T b){

return a+b;

}


--> 메인 에서 int형으로 호출했을 경우 

int Add(int a, int b){

return a+b;

}

--> 메인에서 double형으로 호출했을 경우

int Add(char a, char b){

return a+b;

}

                                 --> 와 같은 함수가 만들어 진다. --> 템플릿을 기반으로 함수가 만들어진다. (컴파일러에 의해)

--> 다음 번에 또 int 형으로 불려졌을 때, 다시 만들어지지 않고 만들어져 있는 놈이 불려온다.

--> double형으로 호출 했을 경우 위와 같이 double형으로 함수 템플릿이 인스턴스화 된다.

--> 클래스도 똑같은 원리


--> 이와 가이 함수 템플릿을 기반으로 실제 호출이 가능한 함수들을 가리켜 템플릿 함수라고 한다.

--> 함수가 만들어 지는 현상을 가리켜서 함수 템플릿의 인스턴스화 라고 부른다.


--> 템플릿은 컴파일러에 의해 처리된다.

--> 따라서 헤더와 정의를 분리할 수 없다. --> 분리 컴파일을 가능하게 하는 것은 링커이기 때문에

--> 하나의 파일 내에 정의와 선언이 같이 있어야 한다.





'C++' 카테고리의 다른 글

[C++] API란?  (0) 2016.12.15
[C++] 예외처리 // 열혈강의  (0) 2016.12.14
[C++] 복사생성자 정리  (0) 2016.12.07
[C++] 레퍼런스 정리  (0) 2016.12.07
[C++] 연산자 오버로딩 // 열혈강의  (0) 2016.12.07

+ Recent posts