기본적으로 템플릿은 편의성과 확장성을 모두 만족할 수 있는 기법입니다. 예를 들어 매개변수로 전달받은 두 수를 더하는 함수를 만든다고 가정했을 때 매개변수는 정수형이 올 수도 실수형이 올 수도 있습니다. 이럴 때 함수 오버로딩을 통해 각 매개변수 타입에 대한 함수를 다중 정의할 수 있습니다.
int Add(int a, int b);
double Add(double a, double b);
만약 간단하지 않은 하나의 함수를 여러가지로 다중 정의했을 때 문제가 발생하는 경우 모든 함수를 고치거나 손봐야 하는 경우가 생깁니다. 이럴 경우 사용할 수 있는 것이 템플릿입니다. 템플릿은 아래와 같이 template이라는 키워드를 사용합니다. 이렇게 정의한 코드를 사용자가 호출하면 컴파일러에 의해 다중 정의 코드가 자동으로 만들어지게 됩니다.
template <typename T>
T Add(T a, T b);
사용자는 호출할 때 자료형을 명시해도 되고 안해도 됩니다.
#include <iostream>
using namespace std;
template <typename T>
T Add(T a, T b)
{
return a+b;
}
int main()
{
cout << Add(3,4) << endl;
cout << Add(3.3, 4.4) << endl;
cout << Add<int>(3,4) << endl;
cout << Add<int>(3.3, 4.4) << endl;
}
만약 위와 같이 자료형을 명시한다면 매개변수에 다른 타입을 넣어도 그 자료형에 맞게 캐스팅됩니다.
이 템플릿을 함수뿐 아니라 템플릿에도 적용이 가능합니다. 함수에서 사용하던 것과 다른 점이 있다면 무조건 타입을 명시해 주어야 합니다.
#include <iostream>
using namespace std;
template <typename T>
class valueSave {
public:
valueSave(T value) : m_value(value) {}
T getValue() { return m_value; }
private:
T m_value;
};
int main()
{
valueSave<int> vInt(10);
cout << vInt.getValue() << endl;
valueSave<double> vDouble(11.11);
cout << vDouble.getValue() << endl;
valueSave<int> vCast(13.13);
cout << vCast.getValue() << endl;
}
템플릿을 사용하는 클래스의 선언과 정의를 분리하기 위해서는 아래와 같이 사용합니다.
template <typename T>
class valueSave {
public:
valueSave(T value) : m_value(value) {}
T getValue();
private:
T m_value;
};
template <typename T>
T valueSave<T>::getValue()
{
return m_value;
}
템플릿을 다중으로 사용할 수 있으며 그리고 템플릿으로 받는 값을 하나의 매개변수로도 사용할 수 있습니다.
#include <iostream>
using namespace std;
template <typename T, int nSize>
class valueSave {
public:
valueSave(T value) : m_value(value) {}
T getValue();
void printSize() { cout << nSize << endl; }
private:
T m_value;
};
template <typename T, int nSize>
T valueSave<T, nSize>::getValue()
{
return m_value;
}
int main()
{
valueSave<int, 3> vInt(10);
cout << vInt.getValue() << endl;
vInt.printSize();
}
이 템플릿의 타입과 값을 디폴트로 설정할 수 있습니다.
#include <iostream>
using namespace std;
template <typename T = int, int nSize = 5>
class valueSave {
public:
valueSave(T value) : m_value(value) {}
T getValue();
void printSize() { cout << nSize << endl; }
private:
T m_value;
};
template <typename T, int nSize>
T valueSave<T, nSize>::getValue()
{
return m_value;
}
int main()
{
valueSave<> vInt(10);
cout << vInt.getValue() << endl;
vInt.printSize();
}
템플릿을 사용하면 자료형에 상관없이 함수를 재사용할 수 있다는 장점이 있지만 만약 특정 자료형은 다르게 처리해야 하는 경우도 있습니다. 함수에서 이를 이용하기 위해서는 반환형, 매개변수 타입이 모두 같아야 합니다.
#include <iostream>
using namespace std;
template <typename T>
T Add(T a, T b) { return a+b; }
template <>
char Add(char a, char b)
{
cout << "char template" << endl;
return 'c';
}
int main()
{
cout << Add<int>(3,4) << endl;
cout << Add<double>(3.3, 4.4) << endl;
cout << Add<char>('a','b') << endl;
}
물론 클래스 템플릿에서도 사용할 수 있습니다. 하지만 클래스를 선언할 때 특수화할 클래스에 타입을 명시해 주어야 합니다.
#include <iostream>
using namespace std;
template <typename T>
class valueSave {
public:
valueSave(T value) : m_value(value) {}
T getValue() { return m_value; }
private:
T m_value;
};
template <>
class valueSave<char> {
public:
valueSave(char value) : m_value(value) {}
char getValue() {
cout << "Char Class" << endl;
return m_value;
}
private:
char m_value;
};
int main()
{
valueSave<int> vInt(10);
cout << vInt.getValue() << endl;
valueSave<char> vChar('A');
cout << vChar.getValue() << endl;
}
템플릿 특수화된 클래스에서 선언부와 정의부를 분리할 때는 따로 template <>을 기술하지 않아도 됩니다.
#include <iostream>
using namespace std;
template <typename T>
class valueSave {
public:
valueSave(T value) : m_value(value) {}
T getValue() { return m_value; }
private:
T m_value;
};
template <>
class valueSave<char> {
public:
valueSave(char value) : m_value(value) {}
char getValue();
private:
char m_value;
};
char valueSave<char>::getValue()
{
cout << "Char Class" << endl;
return m_value;
}
int main()
{
valueSave<int> vInt(10);
cout << vInt.getValue() << endl;
valueSave<char> vChar('A');
cout << vChar.getValue() << endl;
}
'Programming > C++' 카테고리의 다른 글
[C++] boost windows 비동기 처리하기 (2) | 2023.10.23 |
---|---|
[C++] Template(2) (0) | 2023.09.22 |
[C++] std::forward_list, std::list (0) | 2023.07.18 |
[C++] std::array, std::vector (0) | 2023.07.12 |
[C++] 람다 함수 (0) | 2023.04.07 |