본문 바로가기

문과 코린이의, [C. C++] 기록/C++ 이론

[문과 코린이의 IT 기록장] C,C++ - 템플릿(Template)에 대한 이해와 함수 템플릿 (함수를 대상으로 템플릿 이해하기, 함수 템플릿과 템플릿 함수, 둘 이상의 형(Type)에 대해 템플릿 선언하기, 함수 ..

반응형

[문과 코린이의 IT 기록장] C,C++ - 템플릿(Template)에 대한 이해와 함수 템플릿 (함수를 대상으로 템플릿 이해하기, 함수 템플릿과 템플릿 함수, 둘 이상의 형(Type)에 대해 템플릿 선언하기, 함수 템플릿의 특수화 (Specialization))

[문과 코린이의 IT 기록장] C,C++ - 템플릿(Template)에 대한 이해와 함수 템플릿 (함수를 대상으로 템플릿 이해하기, 함수 템플릿과 템플릿 함수, 둘 이상의 형(Type)에 대해 템플릿 선언하기, 함수 템플릿의 특수화 (Specialization))

 


1. 함수를 대상으로 템플릿 이해하기

- 함수 템플릿의 특징

: 함수 템플릿은 함수를 만들어 낸다. 

: 함수의 기능은 결정되어 있으나, 자료형은 결정되어 있지 않아서 결정해야 한다.

 * 즉 다양한 자료형의 함수를 만들어 낼 수 있다.

 

1 ) 함수 

int Add(int num1, int num2)
{
	return num1 + num2;
}

- 함수의 기능 : 덧셈

- 함수의 자료형 : int형 

 

2 ) 함수 -> 템플릿 활용

- 이러한 함수를 만들어낼 수 있는 템플릿은 아래와 같이 정의한다.

template <typename T> // T라는 이름을 이용해서 아래의 함수를 템플릿으로 정의하겠다
/* = template <class T> */

T Add(T num1, T num2) // T는 자료형을 결정짓지 않겠다는 의미로 사용
{
	return num1 + num2;
}

- 함수의 기능 : 덧셈

- 대상 자료형 : 결정되어 있지 않음

 

cf ) 함수를 템플릿으로 정의하는 것이, 매 호출마다 함수를 만드는 것은 아니다.


Case 1 )

#include<iostream>
using namespace std;

template <typename T>
T Add(T num1, T num2) {
	return num1 + num2;
}

int main() {
	cout << Add<int>(15, 20) << endl; // T를 int로 해서 만들어진, Add함수를 호출한다.
	cout << Add<double>(2.9, 3.7) << endl; // T를 double로 해서 만들어진, Add함수를 호출한다.
	cout << Add<int>(3.2, 3.2) << endl;
	cout << Add<double>(3.14, 2.75) << endl;

	return 0;
}

 


2. 함수 템플릿과 템플릿 함수

1) 함수 템플릿

- 위에 설명했던 정의

template <typename T>
T Add(T num1, T num2) {
	return num1 + num2;
}

 

2) 템플릿 함수 (template function)

- 위의 템플릿을 기반으로, 컴파일러가 만들어 내는 다음 유형의 함

int Add<int>(int num1, int num2) {
	return num1 + num2;
}

double Add<double>(double num1, double num2) {
	return num1 + num2;
}

- <int>와 <double>은 일반함수가 아니라, 컴파일러가 만들어내는 템플릿 기반의 함수임.

- 즉 템플릿 함수는 템플릿을 기반으로 만들어진 함수를 의미함.

 

 


Case 2 )

#include<iostream>
using namespace std;

template <typename T>
T Add(T num1, T num2) { // 함수 템플릿 형태로 정의됨
	cout << "T Add(T num1, T num2)" << endl;
	return num1 + num2;
}

int Add(int num1, int num2) { // 일반함수의 형태로 정의됨
	cout << "Add(int num1, int num2)" << endl;
	return num1 + num2;
}


double Add(double num1, double num2) { // 일반함수의 형태로 정의됨
	cout << "Add(double num1, double num2)" << endl;
	return num1 + num2;
}

int main() {
	cout << Add(5, 7) << endl; // 일반함수 호출
	cout << Add(3.7, 3.5) << endl; // 일반함수 호출
	cout << Add<int>(5, 7) << endl; // 템플릿 함수 호출
	cout << Add<double>(3.7, 7.5) << endl; // 템플릿 함수로 호출

	return 0;
}

 

※ 주의점 :  템플릿함수와 일반함수는 구분된다.

 


3. 둘 이상의 형(Type)에 대해 템플릿 선언하기

Case 3 )

#include<iostream>
using namespace std;

template <class T1, class T2> 
// 쉼표(,)를 이용해서 둘 이상의 템플릿 타입을 명시할 수 있음
// typename = class

void ShowData(double num) { // 함수 템플릿의 매개변수도 기본 자료형으로 선언될 수 있음
	// 인자로 전달된 num값을, T1과 T2로 명시되는 자료형으로 형 변환해서 출력함
	cout << (T1)num << ", " << (T2)num << endl; 
    /* = cout << T1(num) << ", " << T2(num) << endl;  */
}

int main() {
	// 위의 함수 템플릿의 매개변수형이 double이기 때문에, 선언되는 인자를 통해서는 T1,T2의 자료형을 결정짓지 못함
	// 따라서, 템플릿 함수의 호출형식을 갖추어서 호출해주어야 함.
	ShowData<char, int>(65);
	ShowData<char, int>(67);
	ShowData<char, double>(68.9);
	ShowData<short, double>(69.2);
	ShowData<short, double>(70.4);

	return 0;
}

 


4. 함수 템플릿의 특수화 (Specialization)

Case 4 ) 함수 템플릿에서 문자열 문제

#include<iostream>
using namespace std;

template<typename T>
T Max(T a, T b) {
	return a > b ? a : b;
}

int main() {
	cout << Max(11, 15) << endl;
	cout << Max('T', 'Q') << endl; 
	cout << Max(3.5, 7.5) << endl;
	cout << Max("Simple", "Best") << endl; 
    
	return 0;
}

 

 

위 코드의 문자열 부분에서 이 코드는 아무런 의미를 갖지 못한다.

cout << Max("Simple", "Best") << endl; // 문자열의 경우에는 결과에 의미를 지니지 못함

코드의 목적이 문자열의 길이비교인지, 사전편찬 순서 비교인지 결정한 후, 템플릿 함수가 구성되어야 의미가 있다.

// 문자열의 길이비교 목적
const char * Max(const char *a, const char *b){
	return strlen(a) > strlen(b) ? a : b;
}

// 사전편찬 순서 비교 목적
const char * Max(const char *a, const char *b){
	return strcmp(a,b) > 0? a : b;
    // strcmp(a,b) : a가 b보다 크면 0보다 큰 수, 같으면 0, 작으면 0보다 작은 수 출력
}

 

Case 5 ) 함수 템플릿의 특수화 적용

#include<iostream>
using namespace std;

template<typename T>
T Max(T a, T b) {
	return a > b ? a : b;
}

/* 함수 템플릿 Max를, char*형에 대해서 특수화 했다. */
// char*형 템플릿 함수가 필요한 경우에는 별도로 만들지 말고, 이것을 써라
template<>
char* Max<char*>(char* a, char* b) {
	cout << "char * Max<char*>(char *a, char *b)" << endl;
	return strlen(a) > strlen(b) ? a : b;
}

/* 함수 템플릿 Max를, const char*형에 대해서 특수화 했다. */
template<>
const char* Max<const char*>(const char* a, const char* b) {
	cout << "const char * Max<const char*>(const char *a, const char *b)" << endl;
	return strcmp(a, b) > 0 ? a : b;
}


int main() {
	cout << Max(11, 15) << endl;
	cout << Max('T', 'Q') << endl;
	cout << Max(3.5, 7.5) << endl;
	cout << Max("Simple", "Best") << endl;
	// 문자열의 선언으로 인해 반환되는 주소 값의 포인터 형은 const char*이다.
    ex. 이는 char *a = "Simple"이 될 경우 포인터로 원소 변경을 할 수 없기 때문이다.

	char str1[] = "Simple";
	char str2[] = "Best";
	cout << Max(str1, str2) << endl;
	// str1, str2는 변수의 형태로 선언되었다. 따라서 str1,str2의 포인터 형은 char*이다.
	// 배열은 배열 원소 변경이 가능하다. ex. str1[0] ='A' (가능)

	return 0;
}

 


* 유의사항
- 아직 공부하고 있는 문과생 코린이가, 정리해서 남겨놓은 정리 및 필기노트입니다.
- 정확하지 않거나, 틀린 점이 있을 수 있으니, 유의해서 봐주시면 감사하겠습니다.
- 혹시 잘못된 점을 발견하셨다면, 댓글로 친절하게 남겨주시면 감사하겠습니다 :)
반응형