본문 바로가기
Language & Framework & GIT/C++

C++ : 템플릿 & 템플릿 함수

by veganwithbacon 2023. 7. 18.
반응형

템플릿(template) : '형판'이라는 뜻 / ' 본 떠 찍어내기 위해 만들어진 틀' 

C++에서 템플릿은 함수나 클래스 코드를 찍어내듯이 생산할 수 있도록 일반화(generic)시키는 도구다.

 

template키워드를 통해, 중복 함수들을 일반화시킨 함수를 만들어 낼 수 있다.

위와 같은 함수를 템플릿 함수(template function) 또는 재네릭 함수(generic function)이라고 부른다.

 

✅템플릿 선언과 재네릭 타입

template <class T>
template <typename T>

template이란 키워드로 시작해 <class T><typename T>로 재네릭 타입 T를 선언한다.

 

재네릭 타입(generic type)이란 C++의 기본 타입이 아니기에 이것을 일반화시킨 새로운 타입으로 일반 타입이라고 부른다.

template <class T1, class T2, class T3>

 

중복 함수들을 템플릿화하는 과정의 역과정구체화(specialization)이라고 한다.

구체화를 통해 재네릭 함수로부터 구체적인 함수의 소스코드를 만들어 낸다.

구체화를 통해 생성된 함수를 구체화된 함수(specialized function)이라고 부른다.

++ Generic 함수는 사전적 정의로 보통의 함수라기보단 '일반화된 함수'라는 뜻이 맞다.

 


템플릿 함수는 컴파일되지도 호출되지도 않는,  그저 함수의 틀이다.

제네릭 함수를 선언, 컴파일 시점에 구체화시키기 위한 틀을 만드는 것이다.

 

구체화 오류

템플릿으로부터 함수를 구체화 시키는 과정에서 제네릭 타입에 유의해야하는데

다음과 같은 상황에서는 하나의 타입만 사용할 수 있다.

template <class T> void myswap(T & a, T & b)

때문에 아래와 같이 선언하면, 이는 잘못된 호출임을 인지해야한다.

int s=4;
double t=5;
myswap(s, t); //컴파일 오류. s와 t의 타입이 같아야한다

 

  CHECK TIME

더보기

1. 일반화의 역과정을 무엇이라고 하는가?

=> 구체화

 

2.템플릿 함수로부터 구체화된 버전의 함수를 생성하는 과정은 컴파일 시에 처리되는가, 실행 시에 처리되는가?

=> 컴파일 시에

(Compile explorer를 통해 확인가능하다)

 

3. 다음 제네릭 함수 add()가 있다.

template <class T>
T add(T data [], int n){
	T sum = 0;
    for(int i=0; i<n; i++) sum += data[i];
    return sum;
}

다음 코드를 컴파일하면 생성되는 구체화된 버전의 add()함수의 소스는 무엇인가?

double x[] = {1.1, 2.2, 3.3, 4.4, 5.5};
add(x, 5);

=>>

double add(double x[], int 5){
double sum = 0;
for(int i=0; i<n; i++) sum += data[i];
return sum;
}

 

4. 다음 제네릭 함수 sum()으로부터 구체화가 실패하는 경우?

template <class Type>
TYPE sum(TYPE a, TYPE b){~~}

1. int n =sum(2,10);       2.sum('a','b');        3. sum(3.5, 6);       4.sum(0, 1);

 

=> 3번


⏺하나의 제네릭 타입을 가진 경우

- 두 개의 매개 변수로부터 큰 값 구하기 

template <class T>
T bigger( T a, T b) // 두 개의 매개 변수 a, b를 비교하여 큰 값 리턴

이 경우 다음과 같이 한 종류의 타입으로만 사용이 가능하다.

#include<iostream>
using namespace std;

template <class T>
T bigger(T a, T b){ // 두 개의 매개 변수 a,b를 비교하여 큰 값 리턴
  if(a > b) return a;
  else return b;
}

int main(){
	int a =20, b=50;
    char c='a', d='z';
    cout << "bigger(20,50)의 결과는 " << bigger(a,b) << endl;
    cout << "bigger('a', 'z')의 결과는 " << bigger(c,d) << endl;
}

 

- 배열의 합 구하기

template <class T>
T add(T data[], int n) //data []배열에서 n개의 원소를 합한 결과 리턴

첫 매개변수는 재네릭 두번째는 항상 int타입인 경우다.

#include <iostream>
using namespace std;

template <class T>
T add(T data[], int n){ //타입 T의 배열 data에서 n개의 원소를 합한 결과 리턴
   T sum = 0;
   for(int i=0; i<n; i++){
        sum += data[i];
   }
   return sum;
}

int main(){
   int x[] = {1,2,3,4,5}'
   double d[] = {1.2, 2.3, 3.4, 4.5, 5.6, 6.7};
   
   cout << "sum of x[] = " << add(x, 5) << endl;
   cout << "sum of d[] = " << add(d, 6) << endl;
}

 

 

⏺두 개 이상의 제네릭 타입을 가진 경우

template <class T1, class T2>
void mcopy(T1 src [], T2 dest [], int n) // n은 복사할 원소의 개수

템플릿을 선언한 후에 제네릭 타입을 두 가지로 지정해줌으로 같은 타입을 지정할 수도 있지만, 각가 다른 타입을 주어 구체화시킬 수 있다.

#include <iostream>
using namespace std;

template <class T1, class T2>
void mcopy(T1 src[], T2 dest [], int n){ // src[]의 n개 원소를 dest[]에 복사
	for(int i=0; i<n; i++)
    	dest[i] = (T2)src[i];
}

int main(){
	int x[] = {1,2,3,4,5};
    double d[5];
    char c[5] = {'H', 'e', 'l', 'l', 'o'}, e[5];
    
    mcopy(x, d, 5); // int x[]의 원소 5개를 double d[]에 복사
    mcopy(c, e, 5); // char c[]의 원소 5개를 char e[]에 복사
    
    for(int i=0; i<5; i++) cout << d[i] << ' '; //d[] 출력
    cout << endl;
    for(int i=0; i<5; i++) cout << e[i] << ' '; //e[] 출력
    cout << endl;
}

 

중복 함수가 템플릿 함수보다 우선

#include <iostream>
using namespace std;

template <class T>
void print(T array [], int n){
	for (int i=0; i<n; i++)
    	cout << array [i]<< '\t';
    cout <<endl;
}

int main(){
	int x[] = {1,2,3,4,5};
    double d[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
    print(x, 5);  //템플릿의 T가 int타입으로 구체화
    print(d, 5);
    
    char c[5] = {1,2,3,4,5};
    print(c,5); //print() 템플릿의 T가 char타입으로 구체화
}

위 함수에서는 출력값이 char로 표현된 1,2,3,4,5는 char형이 없기 때문에

(int)를 통해 명시적 형변환을 해준다.

 

char 배열의 정수를 출력하는 rpint()를 템플릿 함수와 중복작성하면 템플릿 함수와 이름이 동일한 함수가 중복 시, 컴파일러는 중복된 함수를 템플릿 함수보다 우선 바인딩한다.

#include <iostream>
using namespace std;

template <class T>
void print(T array [], int n){
	for (int i=0; i<n; i++)
    	cout << array [i]<< '\t';
    cout <<endl;
}

void print(char array [], int n){ // 템플릿 함수와 동일한 이름의 함수 중복
	for(int i=0; i<n; i++)
      cout << (int)array[i] << '\t'; //array[i]를 int 타입으로 변환해 출력
    cout << endl;
}


int main(){
	int x[] = {1,2,3,4,5};
    double d[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
    print(x, 5);  //템플릿으로부터 구체화한 함수 호출
    print(d, 5); //템플릿으로부터 구체화한 함수 호출
    
    char c[5] = {1,2,3,4,5};
    print(c,5); // char 배열을 숫자로 출력하는 중복 함수 호출
}

 

 템플릿 함수에 디폴트 매개 변수 사용

template <class T1, class T2>
void mcopy(T1 src [], T2 dest [], int n=5) { //n의 디폴트 값은 5
	for(int i=0; i<n; i++)
    	dest[i] = (T2)src[i];
}

mcopy()는 디폴트 매개 변수를 활용해 다음과 같이 호출할 수 있다.

int x[] = {1,2,3,4,5];
double d[5];
mcopy(x, d); //x[]의 원소 5개를 d[]에 복사

 


다음 함수를 일반화시킨 제네릭 함수를 작성

int add(int x, int y){
	int n = x + y;
    return n;
}

double add(double x, double y){
	double d= x + y;
    return n;
}

답👇

template<class T>
T add(T x, T y){
	T n = x + y;
    return n;
}
반응형

댓글