사용자가 원하는 타입을 넣어주면 그에 맞게 짜여지는 틀과 같은 역할을 한다.
template <typename T>
void print(T w)
{
cout << w << endl;
}
int main()
{
string s;
cin >> s;
print(s);
int a;
cin >> a;
print(a);
}
template <typename T>
class Print
{
public:
Print()
{
}
void pt()
{
std::cout << typeid(T).name() << std::endl;
}
};
int main()
{
Print<std::string> print_s;
print_s.pt();
Print<int> print_i;
print_i.pt();
return 0;
}
위 코드처럼 들어가는 변수의 타입에 맞게 코드가 실행된다.
위 경우들 처럼 클래스 템플릿에 인자를 전달해서 실제 코드를 생성하는 것을 클래스 템플릿 인스턴스화 (class template instantiation)라고 한다.
템플릿을 할 때 일부 경우에 대해선 따로 처리해주는 것이다.
template <typename T, typename A>
class Print
{
public:
Print()
{
}
void pt()
{
std::cout << typeid(T).name() << std::endl;
}
};
template <>
class Print<int, float>
{
public:
Print()
{
std::cout << "float or int~~" << std::endl;
}
};
template <typename B>
class Print<std::string,B>
{
public:
Print()
{
std::cout << "string~~" << std::endl;
}
};
int main()
{
Print<std::string, double> print_s;
Print<int, float> print_i;
return 0;
}
이런식으로 원래 선언한 템플릿의 개수에 맞추어 자신이 따로 처리하고 싶은 경우에 대하여 템플릿 특수화를 진행할 수 있다.
template<typename T, typename Comp>
void bubble_sort(T& cont, Comp& comp)
{
for (int i = 0; i < cont.size(); i++)
{
for (int j = i + 1; j < cont.size(); j++)
{
if (!comp(cont[i], cont[j]))
{
int temp = cont[i];
cont[i] = cont[j];
cont[j] = temp;
}
}
}
}
bool comp1(int a, int b)
{
return (a > b);
}
bool comp2(int a, int b)
{
return (a < b);
}
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(4);
v.push_back(2);
v.push_back(6);
v.push_back(3);
bubble_sort(v, comp1);
for (int i = 0; i < v.size(); i++)
{
std::cout << v[i] << std::endl;
}
코드를 입력하세요
bubble_sort(v, comp2);
for (int i = 0; i < v.size(); i++)
{
std::cout << v[i] << std::endl;
}
return 0;
}
함수 객체가 없었다면 오름차순, 내림차순 정렬에 대하여 만들어줘야 하지만(함수포인터를 쓸 필요없이) 사용자가 원하는 조건에 대한 클래스를 만들어 주어서 실행할 수 있다는 점에서 더 간편하고 효율적이다.
template<typename T, int num>
void print(T s)
{
std::cout << s << " " << num << std::endl;
}
int main()
{
std::string s;
std::cin >> s;
print<std::string, 5>(s);
return 0;
}
이와 같이 템플릿에 전달하는 인자가 타입이 아닌 정수와 같은 변수도 가능하다. 정수 이외에도(c++ 20부터) 밑에 있는 여러 자료형들도 사용이 가능해졌다. ->컴파일 타임에 값들이 정해져야 하는 것에 많이 사용
ex)STL의 array 경우 std::array<int, 2> arr 이런 식으로 미리 크기를 알려줄 수 있다.
정수 타입들 (bool, char, int, long 등등). 당연히 float 과 double 은 제외
포인터 타입
enum 타입
std::nullptr_t (널 포인터)
만약 아무 값도 전달해주지 않으면 컴파일 오류가 생긴다.
이를 방지하기 위해
미리 디폴트 값을 정해두어 아무 값도 전달하지 않아도 실행될 수 있게 할 수 있다.
template<typename T, int num = 5>
void print(T s)
{
std::cout << s << " " << num << std::endl;
}
int main()
{
std::string s;
std::cin >> s;
print<std::string>(s);
return 0;
}
타입 또한 디폴트로 전달이 가능하다.
최소값을 구하는 함수를 만들 때
template<typename T>
struct Compare
{
bool operator()(const T& a, const T& b) const { return a < b; }
};
template<typename T, typename Comp = Compare<T>>//디폴트로 설정해준 타입에 따라서 클래스가 실행됨
T Min(T a, T b) {
Comp comp;
if (comp(a, b)) {
return a;
}
return b;
}
int main()
{
int a = 3, b = 5;
std::cout << "Min " << a << " , " << b << " :: " << Min(a, b) << std::endl;
std::string s1 = "abc", s2 = "def";
std::cout << "Min " << s1 << " , " << s2 << " :: " << Min(s1, s2)
<< std::endl;
return 0;
}
<출처>