템플릿이란?
: 함수나 클래스를 개별적으로 작성하지 않아도, 여러 자료형으로 사용할 수 있도록 만들어 놓은 틀
- 함수 템플릿
- 클래스 템플릿
- 컴파일 시간에 ~
- 객체의 자료형을 인수로 처리함
1. Function Template
- 함수를 만들어낼 때, 함수의 기능은 명확하지만, 자료형을 모호하게 두는 것.
- 템플릿으로 사용하는 변수가 2개 이상일 경우, 함수이름 뒤에 <>안에 명확하게 사용하지 않는다.
→ 컴파일러가 스스로 자료형 판단
- template 선언 시 <typename T>, <class T> 둘 다 사용 가능
기본 문법
template <typename T>
T functionName (T parameter1, Tparameter2, ...) {
// code
}
a = functionName<int> (4,6);
b = functionName<double> (4.4, 6.6);
Different return Type
2. Class Template
기본 문법
template <typename T>
class className {
private:
T var;
public:
T functionName (T arg);
};
- 오버로딩과 다르게 '다른' 함수로 취급된다.
- 디폴트 템플릿 인자를 명시할 수 있음. template<typename T = int > 는 디폴트 템플릿 인자가 int 임
- 기초 클래스로 상속할 수 있음.
- 함수 템플릿을 호출할 때와 달리, 클래스 템플릿을 사용할 때는 반드시 타입을 명시해야 함.
≫ 클래스의 생성자가 호출되기 이전에 멤버 변수의 타입을 확인해, 객체의 메모리 공간을 할당해야 할 필요가 있기 때문이다.
non-type parameter
#include <iostream>
using namespace std;
template <typename T>//class Array 정의
//template<typename T, int arraySize>//arraySize는 멤버변수처럼 사용될 수 있음
//template은 템플릿 데이터 타입 + 어떠한 primitive data types을 받을 수 있음 !
class Array {
public:
explicit Array(int size) : arraySize{ size } {
ptr = new T[arraySize];//배열을 가리키는 포인터
}
int getSize() const {
return arraySize * sizeof(T);
}
~Array() {
delete[] ptr;
}
private:
T* ptr = nullptr;
int arraySize = 0;
};
int main() {
Array<int> arr1{ 5 };//Array<int>타입의 객체 생성
//Array <int, 5>arr1;
cout << arr1.getSize() << endl;
Array<double> arr2{ 5 };
cout << arr2.getSize() << endl;
return 0;
}
Type Inference
3. Specialization
- 함수 템플릿과 클래스 템플릿는 특정 데이터 타입으로 그것의 버전을 정의할 수 있다.
- 컴파일러는 템플릿 버전을 우선적으로 체크한 후, 메인 템플릿을 체크한다.
- 함수 템플릿 -> 명시적 특수화 가능, 부분 특수화 불가능
※ 오버로딩으로 해결할 수 있음. 명시적 특수화된 함수보다 위에 있을 것!!
- 클래스 템플릿 -> 명시적 특수화, 부분 특수화 가능
순서 : 일반함수 > 템플릿 특수화 함수 > 템플릿 알맞은 함수
- 완전 특수화 → 템플릿 매개 변수들을 전부 다 특수화 함
- 부분 특수화 → 템플릿 매개 변수들이 여러개일 때 그 중 일부만 특수화 함
- 전역 함수의 경우 문제 없이 가능
- 멤버 함수의 경우 클래스 외부에선 부분 특수화 불가능
- 클래스 내부에서만 가능하므로 상속을 이용함
template <typename T>
class className {
T functionName (T arg);
};
template <>
class className <int> {
int functionName (int arg);
};
/ Example. char * Specializtion /
#include <iostream>
using namespace std;
template <typename T>//main
T add(T a, T b) {
return a + b;
}
template<>//specialization
const char* add(const char* a, const char* b){
return "char*";
}
int main() {
cout << add(1, 2) << endl;
cout << add("rlo", "lo") << endl;
}
/* 출력
3
rlo lo*/
- 인자 수 다를 수 있음
- 특수화 템플릿에 기본 parameter 표시 x (main template 승계)
/ Example . 클래스 명시적 특수화
#include <iostream>
using namespace std;
// 클래스 템플릿
template <typename T>
class MyClass {
private:
T x;
public:
MyClass(T _x);
T Caldouble();
};
// double 형에 대한 명시적 특수화
template <>
class MyClass<double> {
private:
double x;
public:
MyClass(double _x) { x = _x; }
double Caldouble() {
cout << "double 형 데이터를 2배하여 출력합니다. " << endl;
return x * 2;
};
};
/ Example. 클래스 부분적 특수화
// 3개의 인자를 가지는 클래스 템플릿 예
// 일반적인 클래스 템플릿
template <typename A, typename B, typename C>
class MyClass {};
// 첫 번째 인자에 대한 특수화 - A가 int일 경우
template <typename B, typename C>
class MyClass<int> {};
// 첫 번째, 세 번째 인자에 대한 특수화 - A가 int, C가 double일 경우
template <typename B>
class MyClass<int, B, double> {};
// 모든 인자에 대한 특수화 - A가 int, B가 int, C가 double일 경우
template <>
class MyClass<int, int, double> {};
//Example. const char*
#include <iostream>
#include <exception>
#include<stdexcept>
using namespace std;
template <typename T>
class MyData {
public:
explicit MyData(T value) : data{ value } {}
T getData() const { return data; }
private:
T data;
};
template <>
class MyData<char*> {
public:
explicit MyData(const char* value) : data{ new char[strlen(value)] } {
strcpy_s(data, strlen(value)+1, value);//널문자 포함 목적지 버퍼의 크기 전달
}
const char* getData() const { return data; }
~MyData() { delete[] data; }
private:
char* data;
};
int main() {
cout << MyData{ 5 }.getData() << endl;
cout << MyData<char*>{"dlwlrma"}.getData() << endl;
}
'Major S-T-U-D-Y > OOP2' 카테고리의 다른 글
Exception Handling (0) | 2024.05.23 |
---|---|
Abstraction & Encapsulation (0) | 2024.05.22 |