Coding Feature.

C++) Template. 본문

Programming Language/C & C++

C++) Template.

codingfeature 2023. 9. 12. 19:33

Template

템플릿(Template)이란 사용자가 템플릿 매개 변수에 대해 제공하는 인수를 기반으로 컴파일 시간에 일반 형식 또는 함수를 생성하는 구문이라고 한다.

 

즉 컴파일러가 컴파일 도중 사용자가 지정한 규칙(템플릿)을 기반으로 코드에 어떤 코드를 직접 써주는 것을 의미한다.

 

템플릿은 다음과 같은 상황에서 쓰이면 좋다.

void PrintSomething(int A){
	std:: cout << A;
}

int main(){
	PrintSomething(100);		// 출력 '100'
	PrintSomething("Print ME!");	// 에러
	return 0;
}

위에서 인자에 어떤 값을 받고 그 값을 그대로 출력하는 함수 PrintSomething이 있다. 인자 type을 int로만 선언했기 때문에 "Print ME!" 와 같은 string type을 전달하려고 하면 에러가 뜬다.

 

위를 해결하기 위해서는 다음과 같이 코드를 추가로 작성할 수 있을 것이다.

void PrintSomething(int A){
	std:: cout << A;
}

// ***추가***
void PrintSomething(std::string A){
	std:: cout << A;
}

int main(){
	PrintSomething(100);		// 출력 '100'
	PrintSomething("Print ME!");	// 에러
	return 0;
}

함수와 인자의 이름은 모두 같지만 인자의 type만 다르게 해서 함수를 선언했는데 이는 C++ 언어가 함수 오버로딩(Function Overloading)을 지원하기 때문이다. 오버로딩이란 동일한 이름의 함수를 둘 이상 지정할 수 있는 것이다.

 

이렇게 인자의 타입을 따로 작성하는 방법도 충분히 사용가능하지만, 함수는 하나만 선언하고 인자를 건내주는데 그 타입은 컴파일러가 나중에 알아서 그에 맞게 넣어주도록 작성할수도 있다. 그게 바로 Template이다.

template <typename T>
void PrintSomething(T A){
	std:: cout << A;
}

int main(){
	PrintSomething(100);
	PrintSomething("Print ME!");
	PrintSomething(10.5);
	PrintSomething('c');
	return 0;
}

위와 같이 템플릿으로 type 이름을 T로 선언해주면 아래 main 함수에서 건내주는 인자 값들에 대해서 모두 정상적으로 출력이 되는 것을 확인할 수 있다.

 

만약 함수 인자로 전달하는 값의 타입을 명시하고 싶다면 다음과 같이 앞에 '<인자 타입>'을 붙이면 된다.

template <typename T>
void PrintSomething(T A){
	std:: cout << A;
}

int main(){
	PrintSomething<int>(100);
	PrintSomething<std::string>("Print ME!");
	PrintSomething<float>(10.5);
	PrintSomething<char>('c');
	return 0;
}

 

위와 같이 같은 기능을 하는 함수에 대해서 서로 다른 인자의 타입을 선언해줄 때 사용하는 Template을 함수 템플릿(Function Template)이라고 한다.

 

여기서 T는 템플릿 매개 변수이고, typename은 매개 변수의 형식을 의미한다.(typename은 형식의 자리 표시자임을 의미.)

 

원형은 다음과 같다.

template <typename 타입이름> // 보통 타입 이름으로 'T'를 사용.
function{
}

 

 

템플릿은 함수 뿐 만이 아니라 클래스를 생성할 때에도 적용이 가능하다.

template<typename T>
class SomeClass{
private:
	T _N;
public:
	SomeClass(T n) : _N(n){}
	T GetN() const {return _N;}
};

int main(){
	SomeClass someClassInt(5);
	std:: cout << someClassInt.GetN();

	SomeClass someClassFloat(9.8f);
	std:: cout << someClassFloat.GetN();

	SomeClass someClassString("Hello Template!");
	std:: cout << someClassString.GetN();
	return 0;
}

SomeClass라는 클래스의 private 변수의 타입을 T로 정의하고, 객체를 초기화할때 넘겨주는 값에 따라 타입이 달라지도록 할 수 있다.

 

위와 같이 클래스에 대해서 템플릿으로 정의하는 것을 클래스 템플릿(Class Template)이라고 한다.

 

 

클래스 템플릿을 사용해서 다음과 같은 유용한 일을 할 수 있다.

 

만약 어떤 클래스 내에서 멤버 변수로 정적 배열을 사용할 때, 이는 컴파일 타임에서 스택에 할당되기 때문에 미리 배열의 크기를 명시해야했다. 하지만 템플릿을 사용한다면 다음 코드와 같은 일이 가능해진다.

template<typename T, int N>
class SomeArray{
private:
	T _array[N];
public:
	int GetN() const {return N;}
};

int main(){
	SomeArray<int, 6> someArray;	// array의 타입명은 int, array의 사이즈는 6으로 초기화.
	std:: cout << someArray.GetN();
	return 0;
}

객체를 생성할 때 배열 안에 담길 값의 타입은 물론, 배열의 크기까지 명시해줌으로써 객체마다 다른 배열의 크기를 지정해 줄 수 있게 되었다. 이는 컴파일이 될 때 컴파일러가 템플릿 매개변수에 대해서 직접 그 값을 넣어주고 컴파일하기 때문이다.

 

실제로 컴파일할 때 위 코드는 다음과 같은 코드로 바뀌는 것과 같다. (단 클래스 객체를 생성할 때에만)

class SomeArray{
private:
	int _array[6];					// T가 int로, N이 6으로 바뀜.
public:
	int GetN() const {return 6;}
};

 

 

참고자료.

https://www.youtube.com/watch?v=I-hZkUa9mIs&t=292s

https://learn.microsoft.com/ko-kr/cpp/cpp/templates-cpp?view=msvc-170#type_parameters 

 

템플릿 (C++)

자세한 정보: 템플릿(C++)

learn.microsoft.com