#include <iostream>
using namespace std;
// [class] this is just original template
template <typename alpha, typename beta>
class A {
public:
A(alpha one, beta two) {
cout << " ========= original template A class constructor =========== " << endl;
cout << "one : " << one << ", two : " << two << endl;
}
};
// [class] this is partial specialization
template <typename alpha>
class A<double, alpha> {
public:
A(alpha one, double two) {
cout << " ========= specialization partial template A class constructor =========== " << endl;
cout << "one : " << one << ", two : " << two << endl;
}
};
// [class] this is entire specialization
template <>
class A<char*, char*> {
public:
A(char* one, double two) {
cout << " ========= specialization entire template A class constructor =========== " << endl;
cout << "one : " << one << ", two : " << two << endl;
}
};
// [function] this is original_function template
template<typename alpha, typename beta, typename gamma>
int function_A(alpha one, beta two, gamma three) {
cout << "======== function original template ==========" << endl;
alpha result = one + two + three;
return result;
}
// [function] this is entire_specialization template
template<>
int function_A<int, int, double>(int one, int two, double three) {
cout << "======= function entire specialization template ========" << endl;
int result = one + two + three;
return result;
}
//// 템플릿 함수의 오버로딩, 사용하지 않거나, 템플릿 함수의 특수화와 고려해서 사용하는것을 권장 드린다.
//// [function] this is original_function template, but overloading function_A
//template<typename alpha, typename beta, typename gamma>
//int function_A(int one, int two, int three) {
// cout << "======= function overloading template ========" << endl;
//
// int result = one + two + three;
// return result;
//}
//
//// 함수의 부분 특수화는 불가능 하다
//template<typename alpha>
//alpha function_A<int>{
//
//}
int main() {
char temp[] = "rorododo";
// 클래스 기본 템플릿 사용
A<int, int> original2(300, 400);
// 클래스 부분 특수화
A<double, int> partial_specialization_1(5, 15.5);
// 클래스 전체 특수화
A<char*, char*> entire_specialization_1(temp, 20.2);
// 함수 기본 템플릿 사용
cout << function_A<double, double, double>(10, 20, 30) << endl; // 해당 정수들을 double 형으로 바꿔보면서 테스트 해 보세요!
// 위의 함수 오버로딩 역시 주석 해제해야 함.
// 함수의 전체 특수화 (함수는 전체 특수화밖에 안된다. 부분특수화 불가)
cout << function_A<int, int, double>(10, 20, 30.3) << endl;
}
템플릿의 특수화가 무엇인지 검색하고 들어오신 분들이라면 템플릿의 개념을 모두 아시리라 생각됩니다.
짧게 짚고 넘어가자면 '형(shape)' 이 다른 여러 변수들을 하나의 함수 / 클래스에서 사용하게 하기 위해서, 즉 '편의' 를 위해 만들어진것이 템플릿 이며 템플릿에서도 '특수화' 라는 개념이 있습니다. 이해를 위해 코드를 덧붙여 드리면
template<typename alpha, typename beta, typename gamma>
class A
{
A(alpha one, beta two, gamma three) { //주저리 주저리... }
};
//음... 클래스 템플릿을 이용할때 두번째 변수가 double 인것에 대해서만 예외적으로 처리해야 할 것 같은데... 어떻게 하지?
template<typename alpha, typename gamma>
class A<alpha, double, gamma>
{
A(alpha one, double two, gamma three) { // 이렇게 처리하면 쉽네!
}
위와 같이 사용될 수 있습니다. 즉, 그냥 템플릿 내에서 오버로딩을 위해 사용 되는 것 입니다.
보통의 오버로딩을 진행하려면
int add(int x, int y); // integer version
double add(double x, double y); // floating point version
출처: https://boycoding.tistory.com/221 [소년코딩]
이와같이 오버라이딩 / 오버로딩을 진행 합니다. 하지만 'shape' 가 다른 파라미터들을 유동적으로 사용하면서 동시에 오버로딩도 사용하고 싶다면 템플릿을 사용하면서 특수화를 사용하는것이 해결책이 될 수 있습니다.
+ 함수 템플릿은 '전체 특수화' 만 이용할 수 있고, 부분 특수화는 이용할 수 없습니다.
++ 함수 템플릿의 특수화는 / 오버로딩과 선택적으로 사용해야 만 합니다.
이유는 위키독스에 자세~히 기술되어 있지만 짧게 한줄 요약 하자면
"디버깅이 힘들어 집니다."
맨 위 코드에서 두 함수들의 주석을 풀거나 다시 주석화 한 뒤 테스트 해 보세요. 결과가 굉장히 난해 할 겁니다. 이게 바로 위키독스에서 설명하는 "가장 구체적인 녀석" 을 선택해서 실행시킨다 는 개념 때문인데. 지금이렇게 몇줄 안되는 코드에서야 대~강 어떤 함수가 실행되는지 눈에 보이지만.
만약 여러분이 대규모 프로젝트에 참여해서 SDK 같은녀석을 만든다고 가정하면 여러분이야 이해하기 쉽겠지만 같이 협업하는 개발자나 / 그 SDK 를 사용하는 프로그래머 입장에서는 벽이 하나 늘어나는 것입니다.
더하여 명심해야 하는 점은 오버로딩된 템플릿 함수는 또 하나의 오리지널 함수라는 뜻 입니다. 더 쉽게 이미지로 설명 드리면
위와 같이 설명드릴 수 있습니다. 위키독스에서 설명드리는 [지침] 에 들어있는 설명과 일치하는데
특수화는 그 기본 템플릿이 선택된 후에만 쓰이며,
기본 템플릿을 선택하는 과정에서 기본 템플릿이 특수화들을 가지고 있는지의 여부는 고려되지 않습니다.
때문에 블로그 장 역시 함수 템플릿 특수화를 사용해야 할 때는
1. 함수 템플릿 특수화만 사용한다
2. 함수 템플릿 오버로딩만 사용한다
둘 중 하나만을 사용하시는것을 권장 드립니다.
+++
전체 특수화 한 템플릿은 파라미터에 기본 셋팅을 명시할 수 없습니다.
// ConsoleApplication1.cpp : Defines the entry point for the console application.
//
#include <iostream>
using namespace std;
template<typename T>
int a(T x = 10){
return x;
}
template<typename T>
int f(T, T x = 50){
return x;
}
template<typename T>
int g(T, T x = 40){
return x;
}
//template<>
//int g(int, int y = 100){
// return y / 2;
//}
int main()
{
std::cout << a<int>(100) << std::endl;
std::cout << f<int>(600) << std::endl;
std::cout << g<int>(300) << std::endl;
}
따라서 에러라 주석처리한 곳에 실제로 에러가 발생하는 것을 살펴 보실 수 있습니다.
하지만 기본 템플릿에 기본 인자가 명시 되었다면, 명시적 특수화가 이루워 진 뒤에도 계속 사용하는것이 가능 합니다.
-- 출력 값--
근데 뭣같이 복잡해지니 가능하면 기본 템플릿을 이용하여 특수화 템플릿에 기본 인자를 부여하는 방법은 사용하지 않는편이 좋다 생각 됩니다.
코드 내에서 주석으로 entire 라는 명칭을 썻는데, 그냥 짧은 식견으로 기술한것이고
보통은 explict specialization 혹은 full specialization 으로 사용합니다.
'Programming > C++' 카테고리의 다른 글
[C++] constexpr 사용하기. (0) | 2020.11.22 |
---|---|
[C++] 함수 포인터 (0) | 2020.11.01 |
[C++] C++ 이 끔찍한 언어라 욕을 먹는 이유. (0) | 2020.09.30 |
[C++] system, WinExec 함수 출력값 받는법. (0) | 2020.08.17 |
어떻게 특정 .h 가 dll, lib 와 매칭되는지 알 수 있나? (0) | 2020.07.14 |