[C++] 템플릿 (Template)

Taeil Nam·2022년 11월 29일
0

C++

목록 보기
12/13
post-thumbnail

템플릿 (Template)

함수와 클래스가 특정 자료형을 사용하지 않고 여러 자료형을 가질 수 있도록 함.
(제네릭 프로그래밍 (Generic Programming))

  • 컴파일 타임에 컴파일러가 함수와 클래스에서 필요한 자료형이 무엇이 있는지 판단 후, 해당 자료형들을 사용하는 함수와 클래스를 각각 만듦.
  • 여러 자료형의 함수를 만들어내는 함수 템플릿과, 여러 자료형의 클래스를 만들어내는 클래스 템플릿이 있음.
  • 템플릿에 의해 만들어진 여러 함수, 클래스를 템플릿 인스턴스 라고 함.

함수 템플릿 (Function Template)

여러 자료형의 함수를 만들어내기 위한 템플릿.


템플릿이 없는 경우

어떤 자료형이 들어올지 모르기 때문에, 모든 자료형에 대해 함수 오버로딩 필요.

코드

#include <iostream>
using namespace std;

void Print(int a, int b)
{
	cout << a << ',' << b << endl;
}

void Print(double a, double b)
{
	cout << a << ',' << b << endl;
}

void Print(const char* a, const char* b)
{
	cout << a << ',' << b << endl;
}

int main()
{
	Print(1, 2);
	Print(1.1, 2.2);
	Print("Taeil", "Nam");

	return 0;
}

결과


함수 템플릿 사용

template 키워드 사용.
typename으로 만들어준 'T' 자료형을 사용하면, 'T' 자료형이 특정 자료형으로 변경된 새로운 함수가 만들어짐.

코드

#include <iostream>
using namespace std;

template<typename T> // 템플릿으로 T라는 typename 지정.
void Print(T a, T b) // 두 매개 변수의 자료형을 T로 지정.
{
	cout << a << ',' << b << endl;
}


int main()
{
	Print(1, 2); // Print(int a, int b) 를 호출한 것과 같음.
	Print(1.1, 2.2); // Print(double a, double b) 를 호출한 것과 같음.
	Print("Taeil", "Nam"); // Print(const char* a, const char* b) 를 호출한 것과 같음.

	return 0;
}

결과


함수 템플릿 명시적 사용

호출자가 직접 자료형을 명시적으로 지정하여 함수 호출.
동작은 함수 템플릿 사용과 동일.

코드

#include <iostream>
using namespace std;

template<typename T> // 템플릿으로 T라는 typename 지정.
void Print(T a, T b) // 두 매개 변수의 타입을 T로 지정.
{
	cout << a << ',' << b << endl;
}


int main()
{
	Print<int>(1, 2); // Print(int a, int b) 를 명시적 호출.
	Print<double>(1.1, 2.2); // Print(double a, double b) 를 명시적 호출.
	Print<const char*>("Taeil", "Nam"); // Print(const char* a, const char* b) 를 명시적 호출.

	return 0;
}

템플릿 매개 변수 추가 사용

템플릿도 함수처럼 여러 개의 매개 변수 사용 가능.

코드

#include <iostream>
using namespace std;

template<typename T1, typename T2> // 템플릿 매개 변수 T1, T2 지정.
void Print(T1 a, T2 b) // 두 매개 변수의 자료형을 각각 T1, T2로 지정.
{
	cout << a << ',' << b << endl;
}


int main()
{
	Print(1, "Taeil"); // Print(int a, const char* b) 를 호출.
    
	return 0;
}

결과


함수 템플릿 특수화

템플릿으로 만든 함수를 모든 자료형이 사용할 수 있는 건 아님.
함수에 정의되어 있는 연산이 가능한 자료형이어야 함.
특정 자료형만 따로 처리하려면, 함수 템플릿 특수화 사용.

예시

  • 아래 Print 함수를 사용하기 위한 자료형은, << 연산자 오버로딩을 가지고 있어야 함.
  • 즉, Point 객체는 해당 함수 사용 불가.
class Point
{
public:
	Point(int x, int y) : _x(x), _y(y) { }
	void Print() { cout << _x << ',' << _y << endl; }

private:
	int _x = 0;
	int _y = 0;
};

template<typename T>
void Print(T a)
{
	cout << a << endl; // Point 객체는 '<<' 연산자 오버로딩이 없으므로 사용불가.
}

함수 템플릿 특수화 사용

#include <iostream>
using namespace std;

class Point
{
public:
	Point(int x, int y) : _x(x), _y(y) { }
	void Print() { cout << _x << ',' << _y << endl; }

private:
	int _x = 0;
	int _y = 0;
};

template<typename T>
void Print(T a)
{
	cout << a << endl;
}

template<> // 함수 템플릿 특수화
void Print(Point a)
{
	a.Print();
}

int main()
{
	int a = 1;
	double b = 3.14;
	const char* c = "nam";
	Point p(5, 5);

	Print(a);
	Print(b);
	Print(c);
	Print(p);

	return 0;
}

결과


클래스 템플릿 (Class Template)

함수 템플릿과 동일하다.. 함수->클래스로 바꿔서 생각 하면 됨.


큐 구현

클래스 템플릿을 사용해서 아주 간단하게 큐를 흉내내보는 예제.

코드

#include <iostream>
using namespace std;

template<typename T> // 클래스 템플릿
class Queue
{
public:
	void Push(T data)
	{
		_buffer[_i++] = data;
	}
	
	T Pop()
	{
		T result = _buffer[_pop];
		_buffer[_pop++] = 0;
		return result;
	}

	bool Empty()
	{
		return (_pop == 10);
	}

private:
	T _buffer[10];
	size_t _i = 0;
	size_t _pop = 0;
};

int main()
{
	Queue<int> q;

	q.Push(10);
	q.Push(20);
	q.Push(30);

	if (!q.Empty())
		cout << q.Pop() << endl;
	if (!q.Empty())
		cout << q.Pop() << endl;
	if (!q.Empty())
		cout << q.Pop() << endl;

	return 0;
}

결과

0개의 댓글