본문 바로가기
CPP

CPP Template

by yongckim 2021. 12. 9.
728x90
반응형
일반화 프로그래밍(Generic Programing)

데이터 형식에 의존하지 않고 하나의 값이 여러 다른 데이터 타입들을 가질 수 있는 기술에 중점을 두어 재사용성을 높일 수 있는 프로그래밍 방식을 의미합니다.

CPP에서 템플릿을 이용하여 일반화 프로그래밍을 할 수 있습니다.

템플릿(Template) 이란?

템플릿은 매개변수 타입에따라 동작하는 하나의 틀을 만드는 것을 의미합니다.

자료형이 모호한 상황에서 기능은 확실한 함수나 클래스를 만들려고 할때 템플릿을 사용하여 여러 자료형에 동작하는 함수나 클래스를 만들 수 있습니다.

템플릿의 활용

프로그래밍을 하면서 기능은 확실한데 여러 자료형을 사용하고 싶은 상황이 발생할 수 있습니다.

 

예를들어, 두 수를 입력받아 더한 후 반환하는 함수를 만들고 싶다고 가정해봅시다.

 

여태까지는 다음과 같이 함수를 오버로딩하여 해결했을 것입니다.

 

double add(double a, double b) {
	return a + b;
}
int add (int a, int b) {
	return a + b;
}

하지만 위와 같은 방법은 자료형마다 계속해서 해당 하는 자료형으로 계속해서 함수를 만들어 주어야 합니다.

 

예를들어, 두 float 변수를 더하고 싶으면 매개변수로 float를 받고 더한 값을 반환하는 함수를 하나 더 만들어야 합니다.

 

이런 식으로 함수를 만드는 건 굉장히 불편할 것입니다.

 

이럴 때는 CPP의 템플릿 기능을 이용하면 모든 자료형에 유연한 함수를 만들 수 있습니다.

 

위의 add 함수를 template으로 만들어 봅시다.

#include <iostream>

template<typename T>
T add(T &a, T &b) {
	return a + b;
}

int main() {
	double d;
	double i;

	d = 3.14;
	i = 3;
	std::cout << add(d, i) << std::endl;
}

위와 같이 작성하면 double, int, float 등등 자유롭게 사용할 수 있는 함수를 만들 수 있습니다.

 

위에서 작성한 것처럼 템플릿 함수는 다음과 같은 문법으로 정의합니다.

 

template <typename 타입이름>
함수리턴타입 함수이름(매개변수) {
	//내용
}

 

typename 부분에 class가 들어올 수도 있으며, class는 CPP의 표준화 이전에 사용되던 키워드이고 현재 기능상의 차이는 거의 없습니다.

 

템플릿 명시적 특수화(explicit specialization)

CPP의 템플릿은 특정 자료형에 대한 명시적 특수화를 통해서 특정한 자료형에 대한 특별한 동작을 처리할 수 있게 해줍니다.

컴파일러는 호출된 함수에 정확히 일치하는 함수를 발견하면 더는 템플릿을 찾지 않고 해당 함수를 사용합니다.

 

명시적 특수화는 특정 자료형은 다르게 처리해야할때 유용합니다. 예를들어, char *(문자열)이 들어오면 입력받은 두 문자열을 이어 붙이도록 하게 만들 수 있습니다.

 

#include <iostream>
#include <cstring>
#include <cstdlib>

template<typename T>
T add(T a, T b) {
	return a + b;
}

template<>
char *add<char *> (char *s1, char *s2) {
	char *s;
	size_t s1_len;
	size_t s2_len;

	if (!s1 || !s2)
		return (0);
	s1_len = strlen(s1);
	s2_len = strlen(s2);
	s = (char *)malloc(sizeof(char) * (s1_len + s2_len + 1));
	if (!s)
		return (0);
	memcpy(s, s1, s1_len);
	memcpy(s + s1_len, s2, s2_len);
	s[s1_len + s2_len] = '\0';
	return s;
}

int main() {
	double d;
	double i;
	char *s1 = "hello";
	char *s2 = "world";
	d = 3.14;
	i = 3;
	std::cout << add(d, i) << std::endl;
	std::cout << add(s1, s2) << std::endl;
}

출력해보면 위와 같이 char *가 들어올 경우에는 두 문자열을 이어 붙이는 것을 볼 수 있습니다.

 

클래스 템플릿

함수뿐만아니라 클래스도 템플릿으로 작성할 수 있으며 다음과 같은 방식으로 선언할 수 있습니다.

template <class 타입> // class -> typename 로 변경가능
class 클래스 이름 {
 // 클래스 내용
};

 

클래스 템플릿을 이용하면 멤버변수의 자료형을 자유롭게 설정할 수 있습니다. 이 점을 이용하여 다양한 자료형에 대응하는 배열을 만들 수 있습니다.

#include <iostream>

template<class T>
class Array  {
	private:
		T *arr;
		unsigned int size;
	public:
		Array() : arr(NULL), size(0) {}

		Array(unsigned int size) : arr(NULL), size(size) {
			if (this->size)
				this->arr = new T[this->size]();
		}

		Array(const Array<T> &array) : arr(NULL), size(array.size) {
			if (this->size)
				this->arr = new T[this->size];
			for (unsigned int i = 0; i < size; i++)
				this->arr[i] = array.arr[i];
		}

		~Array() {
			if (this->size) {
				delete[] this->arr;
				this->arr = 0;
				this->size = 0;
			}
		}
        
        void display();
		Array<T> &operator=(const Array<T> &array) {
			if (this->n)
				delete[] this->arr;
			this->arr = NULL;
			if (array.n) {
				this->arr = new T[array.n]();
				for (unsigned int i = 0; i < array.n; i++)
					this->arr[i] = array.arr[i];
			}
			this->n = array.n;
			return (*this);
		}
		T &operator[](unsigned int idx) {
			return (this->arr[idx]);
		}

		T const &operator[](unsigned int idx) const {
			return (operator[](idx));
		}
};
int main() {
	Array<int> arr(5);
	Array<double> arr2(5);
	arr[0] = 1;
	std::cout << "int" << std::endl;
	for (int i = 0; i < 5; i++) {
		std::cout << arr[i] << ' ';
	}
	std::cout << std::endl;
	std::cout << "double" << std::endl;
	arr2[0] = 1.3;
	for (int i = 0; i < 5; i++) {
		std::cout << arr2[i] << ' ';
	}
	std::cout << std::endl;
}

클래스 템플릿을 이용하면 위와 같이 다양한 자료형을 받는 배열을 만들 수 있습니다.

 

만약 클래스에서 정의만 해놓고 외부에서 클래스 함수를 작성하고 싶을 경우 템플릿임을 다음과 같이 명시해야 합니다.

template <typename 자료형>
리턴값 클래스이름<자료형>::함수이름(매개변수) {
	// 내용
}

//ex
template<class T>
class Array {
	// ...
    void display();
};

template<typename T>
void Array<T>::display() {
	for (int i = 0; i < size; i++)
		std::cout << arr[i] << std::endl;
}
반응형

'CPP' 카테고리의 다른 글

CPP Standard Template Library - iterator  (0) 2021.12.11
CPP Casts  (0) 2021.12.04
CPP Exception - 3  (0) 2021.11.28
CPP Exception - 2  (0) 2021.11.28
CPP Exception - 1  (0) 2021.11.27