함수를 중복해 매개변수만 바꾸어 사용하면 편하긴 하지만, 비효율적인 동작을 하게 된다.
이를 해결하기 위해 매개변수만 바꾸어 쓸 수 있는 템플릿을 만들어 일반화 할 수 있다.
그 방법에 대해 알아보자!
Template (템플릿)
- 함수나 클래스 코드를 찍어내듯 생산 할 수 있도록 일반화(Generic) 시키는 도구
template <class A>
void myTemplate(A &a, A &b){
A apple;
apple = a;
a = b;
b = apple;
}
//template : 템플릿 선언 키워드 , class : 제네릭 타입 선언 A : 제네릭 타입 이름
//3개의 서로 다른 타입이 사용 되는 중복 함수 예제
template <classT1, classT2, classT3>
template <typename T1, typename T2, typename T3>
//typename 키워드 사용 가능
템플릿 구체화
- 중복 함수들을 템플릿화하는 과정의 역과정
구체화된 함수
- 컴파일러가 함수의 호출문을 컴파일하여, 구체화를 통해 제네릭 함수로부터 구체적인 함수의 소스 코드를 만들어내는데 이 때 구체화를 통해 생성됨
구체화 하여 컴파일 하는 과정
- 컴파일러는 호출문을 컴파일 할 때 해당 함수를 탐색
- 템플릿으로 선언 된 함수 발견
- 1번 호출문에 인자 값을 템플릿의 제네릭 타입에 대입
- 구체화 된 함수의 소스 코드 컴파일하고 해당 함수를 호출
→ 주의!! 제네릭 타입에 유의해야 한다. (매개변수 타입 동일해야 함)
템플릿의 역할
- 템플릿은 그저 함수의 '틀' 이라고 할 수 있다.
제네릭 함수를 선언하고, 컴파일 시점에 구체화 시키기 위함
템플릿의 장단점
- 소프트웨어의 생산성, 유연성 증가 → 함수 작성 용이, 함수 재사용
- 포팅에 취약 → 컴파일러에 따라 템플릿 지원 여부 상이
- 템플릿과 관련된 컴파일 오류 빈약 → 디버깅 어려움
제네릭 VS 일반화 → 제네릭 = 일반화
- 템플릿을 이용해 제네릭 함수/클래스를 만들어 프로그램을 작성하는 것으로,
제네릭은 일반화라고 할 수 있다.
제네릭과 매크로의 차이
- 매크로는 복잡한 함수/클래스를 작성하는 것에 한계 존재 → 타입 안전성 보장 불가, 실행 중 부작용 발생 가능성 높음
반면, 제네릭은 제네릭 타입에 적용되는 실제 타입을 검사하는 구체화 과정을 거치기 때문에 타입 안전성 확보 가능
제네릭 함수 예제 코드
//기본적인 구조
template<class T>
void myswap(T& a, T& b) {
T tmp;
tmp = a;
a = b;
b = tmp;
}
void main() {
int a = 4, b = 5;
myswap(a, b);
cout << "a=" << a << "," << "b=" << b << endl;
double c = 4, d = 5;
myswap(c, d);
cout << "c=" << a << "," << "d=" << b << endl;
}
//문장을 단어로 나누는 함수
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
using namespace std;
bool not_space(int c)
{
return !isspace(c);
}
bool space(int c)
{
return isspace(c);
}
template <class Out>
void split(const string& str, Out os)
{
typedef string::const_iterator iter;
iter i = str.begin();
while(i != str.end() )
{
i = find_if(i, str.end(), not_space);
iter j = find_if(i, str.end(), space);
if(i != str.end())
*os++ = string(i,j);
i=j;
}
}
int main()
{
string s;
// cout에 연결된 ostream_iterator<string>을 split 함수에 전달하여, cout에 출력한다.
// split가 *os에 값을 대입하는 순간 cout에 출력하게 된다.
while(getline(cin,s))
split(s,ostream_iterator<string>(cout,"\n"));
// word_list라는 list에 추가하고자 하는 단어가 string이라면
// split(s,back_inserter(word_list)); 이 처럼 사용가능하다.
return 0;
}
'개발 > C++' 카테고리의 다른 글
[C++] 컨테이너 (vector, map) (0) | 2022.12.09 |
---|---|
[C++] 상속 (0) | 2022.11.27 |
[C++] Static (0) | 2022.11.20 |
[C++] 함수 중복 | 디폴트 매개변수 (feat. 복사 생성자) (0) | 2022.11.13 |
[C++] 객체 치환 / 참조에 의한 호출 / 벡터 (0) | 2022.11.04 |