C++

Template

Nin 2020. 12. 23. 02:47

템플릿(Template)은 메타프로그래밍을 C++이 표현하는 방식이다.

객체지향이라는 개념이 있고 각언어가 객체지향의 개념을 각자의 방식으로 표현한다.

메타프로그래밍이란?

넓은 의미에서 런타임에 수행해야 할 작업의 일부를

컴파일 타임 동안 수행하는 프로그램을 말하기도 한다.

이 말은

int main()
{
   int a = 10 + 10;
}

위의 코드를 컴파일러는 우리의 생각처럼 10에 10을 더해서 a는 20이구나가 아니라

그냥 20이라는 결과값을 넣는다.이와같이 생각 할 수 있다.


템플릿 문법

template<typename T>
void Func(T _Value)
{
   std::cout << _Value << std::endl;
}

위와 같이 사용 한다.


템플릿 이해하기

void Func(int _Value)
{
   std::cout << _Value << std::endl;
}

int main()
{
   Func(582985);
}

템플릿을 int형으로 인자값을 넣고 위의 코드처럼 Func함수를 호출 할 수 있다.

그렇다면

Func("test");

이 함수는 호출 할 수 있을까?당연히 안된다 int형을 넣어줘야 하는데

const char* 형을 넣었기 때문이다.

복습)

문자열이 const char* 인 이유는?

->변하지 않는 상수이기 때문 "test" = "test2" 이 코드가 안되는 것과 같다.

void Func(const char* _Value)
{
   std::count << _Value << std::endl;
}

Func("test") 이 함수를 호출하려면 위의 코드와 같이 만들어 주면 가능해진다.

이와 같이 또 다른 자료형으로 사용하고 싶으면 오버로딩을 이용해서같은 자료형의 인자값을 넣는 방식으로 만들어 줘야 한다.

여기서

template<typename T>
void Func(T _Value)
{
   std::cout << _Value << std::endl;
}

int main()
{
    Func(582985);
    Func("test");
}

템플릿 문법을 사용해서 이렇게 만들어 주면 위의 코드만으로도

Func(582985)와 Func("test") 두 함수 모두 사용이 가능해 진다.

int main()
{
    Func<int>(582985);
    Func<const char*>("test");
}

정확한 함수 호출은 위와 같다.

함수의 경우 템플릿으로 만들었을때 인자추론을 통해서 

알아서 어떤 자료형을 사용하는 알아내는 것이다.


템플릿 동작 원리 알아보기

 

컴파일의 4단계에서

전처리기가 주석과 코드를 정리하고 

컴파일러가 컴파일을 시작하면서 템플릿을 인식하고

Func(582985)를 통해서 int형을 사용하는 템플릿 함수를 알아낸다.(인자추론)

그러면서 이 함수를 동작할 수 있게 함수를 만들어 준다.

void Func(int _Value)
{
   std::cout << _Value << std::endl;
}

 

위와 같이 int를 받는 함수를 만들어 준다.

그리고 Func("test")에서 const char*형을 사용하는 함수 역시 컴파일러가 만들어 준다. 

void Func(const char* _Value)
{
   std::count << _Value << std::endl;
}

이 함수들이 만들어져서 생기고 나서 빌드가 된다.


template<typename T,typename U>
void Func(const T _Value1,const T _Value2,const U _Test)
{
   std::count << _Value1 << _Value2 << _Test << std::endl;
}

int main()
{
   Func(10,20,"test");
}

위와 같이 여러개의 템플릿을 사용할 수 있다.

여기서 만약 Func 서로 다른 자료형 3개를 넣어주면 사용 할 수 없다.

템플릿 함수에서 인자값으로 T를 2개 썻기때문에 Func를 호출할 때

첫번째 인수와 두번째 인수의 자료형은 같아야 한다.

void Func(const int _Value1,const int _Value2,const char* _Test)
{
   std::count << _Value1 << _Value2 << _Test << std::endl;
}

컴파일러가 위와 같은 코드를 만들어 주는 것이다.

만약 템플릿과 본함수가 같이 있다면 (내가 둘다 만들어줬다면)

컴파일러는 템플릿은 무시하고 내가 만든 본함수를 사용한다.


템플릿 클래스

템플릿을 이용해서 클래스를 만들면 헤더에서 모든걸 구현해 놓는것이 일반적이다.

template<typename T>
class TemplateClass
{
public:
   T& Value;
public:
   TemplateClass()
   {
   }
   ~TempalteClass()
   {
   }
};

위를 헤더라고 생각하고 선언하고 cpp에 정의를 하려고 하면 오류가 난다.

이유는 저 클래스의 이름이 TemplateClass라는 이름 하나로 될 수 없기 때문이다.

내가 쓰는 자료형에 맞게 새로운 이름을 갖는다.그렇기 때문에

TempalteClass::TemplateClass() 이런식으로 구현할 수 없다.

내가 int형을 쓴다면 TempalteClass<int>::TemplateClass() 이렇게 cpp에

정의해서 사용할 수 있지만 그렇게 되면 템플릿을 사용하는 의미가 사라진다.

내가 사용하는 자료형에 맞게 모두다 만들어 줘야 하기 때문에


위의 코드들에서 볼 수 있듯이 템플릿은 코드량을 줄여주고

그러기 위해서 만들어졌다.

템플릿의 단점으로는 가독성이 떨어지고 템플릿 함수는

컴파일러가 컴파일 단계에서 만들어내기 때문에

당연히 컴파일 속도가 느려진다.

'C++' 카테고리의 다른 글

자료구조  (0) 2020.12.29
정적,동적 바인딩  (0) 2020.12.23
멤버함수에서 함수포인터 사용  (0) 2020.12.22
Function Pointer(함수 포인터) ,CallBack 함수  (0) 2020.12.22
ClassBytePadding(바이트패딩)  (0) 2020.12.22