[C++] 템플릿(Template)(1)

C++ 2017. 12. 25. 21:31

1] 템플릿에 대한 이해와 함수 템플릿
1. 함수를 대상으로 템플릿 이해하기 

template <typename T>
T Add(T num1, T num2)
{
    return num1 + num2;
}

위 템플릿 함수의 정의는 다음과 같다.
- 기능 : 덧셈
- 대상 자료형 : 결정되어 있지 않음

template <typename T>은 T라는 이름을 이용해서 아래이 함수를 템플릿으로 정의한다는 의미이다.(template <class T> 도 똑같은 의미이다.)

다음은 위 템플릿 함수를 이용해서 여러가지 함수를 만들어 보겠다.

int main(void)
{
    cout<< Add<int>(15, 20) << endl;
    cout<< Add<double>(2.9, 3.7) << endl;
    cout<< Add<int>(3.2, 3.2) << endl;  // 값 손실이 발생되어 6이 출력 됨.
    cout<< Add<double>(3.15, 2.75) << endl;

    return 0;
}

Add<int>(15, 20) 의 의미는 "T를 int로 해서 만들어진 Add 함수를 호출한다."
그래서 위 문장을 실행하면 컴파일러는 함수 하나를 만든다. 그러나 두번째의 Add<int>(3.2, 3.2) 문장은 다시 함수를 만들지 않는다. 기존에 만들어져있던 함수를 사용한다. 
그러나, 컴파일 타임에 함수가 만들어지기 때문에 런타임상 속도 저하를 가져오지 않는다. 

위 main 함수를 다음과 같이 변경해도 상관없다. 

int main(void)
{
    cout<< Add(15, 20) << endl;

    cout<< Add(2.9, 3.7) << endl;
    cout<< Add(3.2, 3.2) << endl; 
    cout<< Add(3.15, 2.75) << endl; 

    return 0;
}

위 코드를 컴파일하면 컴파일러가 자동으로 자료형을 결정해서 함수를 만들어 준다. 

2. 함수 템플릿과 템플릿 함수 
- 함수 템플릿
template <typename T>
T Add(T num1, T num2)
{
    return num1 + num2;
}

- 템플릿 함수
: 함수 템플릿 기반으로 컴파일러가 만들어내는 함수다.
: 컴파일러가 생성해 내는 함수라는 뜻으로 Generated Function으로도 불린다.

int Add<int>(int num1, int num2)
{
    return num1 + num2;
}

템플릿 함수와 일반 함수와 구분이 된다.

위 예제에 다음과 같은 일반함수가 추가되었다고 생각해보자.

int Add(int num1, int num2)
{
    return num1 + num2
}

int main(void)
{
    cout<< Add(5, 7) << endl;  // 일반함수를 호출한다.
    cout<< Add<int>(5, 7) << endl; // 템플릿 함수를 호출한다.

    return 0;
}

3. 둘 이상의 Type에 대해 템플릿 선언하기 

template <class T1, class T2>
void ShowData(double num)
{
    cout << (T1)num << " , " << (T2)num << endl; // 형 변환을 "T1(num)" 이런 형태로도 가능.
}

int main(void)
{
    ShowData<char, int>(65); // A, 65 출력
    ShowDate<short, double>(69.2) // 69, 69.2 출력

    return 0;
}

4. 함수 템플릿의 특수화(Specialization)

template <class T>
T max(T a, T b)
{
    return a > b ? a : b;
}

int main(void)
{
    cout<< Max(11, 15) << endl;  // 15 출력
    cout << Max('T', 'Q') << endl; // T 출력
    cout << Max("Simple", "Best") << endl; // 뭐가 출력될지 모름, 단순 주소값을 비교하기 때문
    
    return 0;
}

이런 경우 문자열의 경우 의도하지 않은 결과가 나타난다. 문자열 길이 비교가 목적이라면 다음과 같이 정의 해야 한다. 

const char* Max(const char* a, const char* b)
{
    return strlen(a) > strlen(b) ? a : b;
}

이렇듯 상황에 따라서 템플릿 함수의 구성방법에 예외를 둘 필요가 있는데, 이 때 사용되는 것이 함수 템플릿의 특수화 이다.

char* 타입과 const char* 타입에 대해서 특수화 해보겠다.

template <class T>
T max(T a, T b)
{
    return a > b ? a : b;
}

template <>
char* Max<char *>(char* a, char* b) // <char *> 생략 가능
{
    return strlen(a) > strlen(b) ? a : b;
}

template <>
const char* Max<const char*>(const char* a, const char* b) // <const char*> 생략 가능
{
    return strcmp(a, b) > 0 ? a : b;
}

"char*, const char*형 함수는 내가 이렇게 제시를 하니 필요한 경우에는 별도로 만들지 말고 이것을 써라" 라는 의미다. 


2] 클래스 템플릿
1. 클래스 템플릿 정의
template <class T>
class Point
{
private:
    T xpos, ypos;
public:
    Point(T x =0, T y=0) : xpos(x), ypos(y) {  }
    
    void ShowPosition() const
    {
        cout<<xpos<<", ">>ypos<<endl;
    }
};

int main(void)
{
    Point<int> pos1(3, 4);
    Point<double> pos2(2.4, 3.6);
    
    return 0;
}

위 예제를 보면 템플릿 함수와 매우 비슷해서 쉽게 이해가 갈것이다. 
다만, 템플릿 함수와 달리 템플릿 클래스의 객체를 생성할 때 <int>, <double>과 같은 자료형 정보를 생략하는것은 불가능하다. 

2. 클래스 템플릿을 파일 분할할 때의 주의점
: 컴파일은 파일단위로 이뤄진다는 사실을 이미 알고 있을 것이다. 그렇다면 밑에 main 함수를 보자.

<main.cpp 파일>
int main(void)

{
    Point<int> pos1<3, 4>;

    return 0;
}

위 파일을 컴파일 하기 위해서는 Point 클래스의 정의 및 구현부분까지 알아야 한다. int 자료형에 맞게 템플릿 클래스를 생성해 내야되기 때문이다. 
만약 Point 클래스의 선언과 구현이 PointTemplate.h PointTemplate.cpp에 나눠져 있다면 두 파일 모두 include 해야 컴파일이 성공한다. 
만약 PointTemplate.cpp 파일을 include하기 싫으면 PointTemplate.h에 Point의 생성자와 멤버함수의 정의를 모두 넣어야 한다. 



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

[C++] 템플릿(Template)(2)  (0) 2017.12.25
[C++] 상속과 다형성  (0) 2017.12.25
[C++] 상속  (0) 2017.12.25
[C++] Friend와 Static 그리고 Const  (0) 2017.12.25
[C++] 복사 생성자(Copy Constructor)  (0) 2017.12.23
Posted by 홍성곤
,