템플릿이란?
: 변수에 타입을 정해주지 않고, 필요한 타입을 컴파일 시간에 정의해서 사용하는 개념.
비유적인 설명, (타 홈페이지에 잘 설명된 부분이 있어 인용)
개인적으로 비유를 들자면 펜중에.. 5색펜 이런거 있잖아요. 펜이 한자루 인데. 여러가지 색(자료형)을 우리가 그때그때 쓸 수 있잖아요. template는 여러개의 색(자료형)을 모아놓은 하나의 펜 케이스 그때그때 다른 색(자료형)을 눌러서 사용할 수 있다.
일반 자료형들이 [왼쪽] 펜들 이라고 생각한다면 -> [오른쪽]에 있는 펜 통! 이 Template 라고 생각하면 이해가 쏙쏙 ?
우리는 그때 그떄 필요할때마다. 각 색(int, double, string 등)을 넣어서 쓰면 됩니다.
출처: https://blockdmask.tistory.com/43 [개발자 지망생:티스토리]
형태와 종류
템플릿, 앵글브래킷, 타입네임 등을 활용한 이런 형태의 템플릿 함수를 흔히 볼 수 있다.
C++ 템플릿의 종류에는
1) Function Template
2) Class Template
3) Alias Template
4) Variable Template
C++20 -> concept (템플릿 프로그래밍을 할 때 실수를 줄여줄 수 있다.)
요약하면 템플릿이란 int float double 과 같은 타입네임이 정해져 있지 않고
그냥 template 라는 함수를 만들어서 쓰는 것이다.
이런 템플릿 타입 네임은 알게 모르게 많이 사용하고 있다.
대표적인 예로 최대값을 사용하는 Max function의 정의를 찾아보면 template을 활용해 만들어져 있다.
또한 대표적인 컨테이너인 vector의 경우에도 template을 사용해 만들어졌다.
1. Function Template
: 템플릿의 가장 간단한 형태. 매개변수 타입 때문에 함수 오버로딩을 제공할 때 가장 유용하다. 함수 오버로딩을 함수 템플릿으로 대체가 가능하기 때문이다.
매개변수 2개의 합을 구해주는 add 함수를 만들어 보자.
int type의 add 함수를 만들어 사용하고 있는데,
도중에 double type의 add가 필요해진다.
double을 받아서 합을 구해주는 함수가 존재하지 않기 때문에
개발자는 함수 오버로딩 기능을 사용해서 똑같은 add 함수를 만들어 줄 수 있다.
(함수이름은 같고 매개변수가 다른 함수 add를 만들어 주는 것.)
하지만 이런 방식의 문제점은 데이터 타입이 늘어날 때마다 계속적으로 function overloading이 되는 함수를 정의해 주어야 한다는 것이다. 더해주기만 하는 add 함수가 데이터 타입 때문에 여러가지의 형태를 가지게 되는 것.
즉 만약 float 타입이 또 필요하면 또다시 float 타입으로 함수 오버로딩을 해주어 한다는 것.
이런 번거로움을 해결해 주는 방법이 바로 function template이다.
템플릿을 만들어 주고 타입네임 T를 써준 후, T를 리턴해주는 add(T a, T b){return a+b;};
이렇게 템플릿을 만들어 주면 이 타입 T에 맞는 함수가 만들어 지는 것이다.
실행해 보면 넘겨진 매개변수에 맞는 합이 결과로 나온다.
그렇다면 문자열도 템플릿으로 더할 수 있을까?
auto 키워드를 사용해서 문자열을 매개변수로 넘겨 보면 컴파일이 되지 않는다.
const character* 가 operator + 에 대한 정의가 없기 때문이다.
템플릿은 미리 모든 것이 만들어져 있는 것이 아니라, 넘겨지는 매개변수의 타입에 따라 컴파일이 되고,
컴파일이 되지 않으면 컴파일 에러를 나타낸다는 것.
그렇다면 언제 어떻게 템플릿 함수가 만들어지는지 알아야 한다.
언제 어떤 방식으로 템플릿 함수가 만들어지는가?
이를 정확하게 알기 위해 compiler explorer를 통해 어셈블리 코드를 살펴보자.
Compiler Explorer
godbolt.org
템플릿 함수를 만들었는데 아무런 어셈블리 코드도 생기지 않는다!!!
int a int b를 받아서 return a+b를 해주는 함수를 만들면 이에 대한 어셈블리 코드는 바로 컴파일 된다.
처음 만든 템플릿 함수에
추가로 메인함수를 만들어서 int a 와 int b를 더해주는 함수를 만드니까
오른쪽에 int type에 맞는 add 함수가 만들어졌다.
또 double을 사용한 add function을 호출하니까 이에 맞는 함수의 어셈블리 코드가 생성이 된다.
즉, 템플릿 함수는 코드로만 존재하다가
이 템플릿 함수를 사용할 때 그 타입에 맞는 함수가 컴파일 되면서 바이너리, 또는 어셈블리로 만들어 지는 것이다.
이와는 별개로 explicit template function instantiation이라는 방법도 있는데 이는 다른 게시글에서 다룰 것이다.
<링크>
또한 템플릿 함수를 사용하기 위해서 이렇게 <> angle bracket을 사용해서 타입을 명시적으로 지정해 주었지만,
타입 없이 템플릿 함수를 사용하는 것도 가능하다.
이렇게 되면 int용 add, double용 add, float용 add가 자동적으로 타입이 지정되어 만들어 지는 것이다.
이렇게 자동적으로 타입을 지정해 주는 것을 type deduction 이라고 하는데,
이 deduction이 레퍼런스, r-value 레퍼런스, std::move, std::forward 등과 결합되어 다양하게 사용되므로 자세한 내용을 알고 있어야 한다.
다음 게시글: Type deduction.
결론
Template Function은 호출이 되기 전까지는 단순 코드로만 존재하고 있다가 호출이 되는 순간 그 타입에 맞춰서 컴파일 또는 instantiation이 된다.