C++ 템플릿 2(저장용,메모용, 윤성우 열혈 C++ 프로그래밍 정리 CH 14)

RisingJade의 개발기록·2022년 3월 1일
0

윤성우 열혈C++ 정리

목록 보기
11/13

Chapter 14. 템플릿 2


14-1. Ch13에서 공부한 내용의 확장

템플릿을 사용한 배열클래스 만들기

별거 없다. 그냥 배열 클래스를 만들었는데 배열 타입이 정해진게 아니고 템플릿으로 변경된 것

14-2. 클래스 템플릿의 특수화

클래스 템플릿 특수화

  • Ch13에서 보았듯이 함수 템플릿을 특수화하는 이유는 특정 자료형에 대해서 구분이 되는 다른 행동을 보이기 위해서이다.
  • 마찬가지로 클래스 템플릿을 특수화하는 이유는 특정 자료형을 기반으로 생성된 객체에 대해, 구분이 되는 다른 행동양식을 적용하기 위해서 이다.
template <class T>
class SimpleClass{
public:
    T SimpleFunc(T num) { ... }
};

template <>
class SimpleClass<int>{ // 함수 템플릿때랑 똑같다. T 부분을 전부 int로 바꿔준다.
public:
	int SimpleFunc(int num){...} 
};

클래스 템플릿 부분 특수화

template <class T1, class T2>
class SimpleClass{
public:
    T1 SimpleFunc(T1 num1, T2 num2) { ... }
};

template <class T1>
class SimpleClass<T1, int>{ // T1은 그대로 템플릿 형식으로 두고, 뒤의 T2만 특수화하여(여기선 int) 쓸 수 있다.
public:
	T1 SimpleFunc(T1 num, int num2){...} 
};

위와 같이 전부 특수화하는것이 아니라 일부분에만 특수화를 적용 시킬 수 있다.

14-3. 템플릿 인자

템플릿을 정의할 때 결정되지 않은 자료형을 의미하는 용도로 사용되는 T 또는 T1, T2와 같은 문자를 가리켜 템플릿 매개변수라고 한다. 그리고 템플릿 매개변수에 전달되는 자료형 정보를 가리켜 템플릿 인자라고 한다.

템플릿 매개변수에는 변수의 선언이 올 수 있습니다.

template <class T1, int len>
class SimpleClass{
private:
	T arr[len];
public:
	T& operator[] (int idx){
    	return arr[idx];
    }
    
};

int main(void){
	SimpleClass<int, 5> i5arr;
    SimpleClass<double, 7> d7arr;
}

위와 같이 class T1이 아닌 int len처럼 쓸 수 있으며, main에서 보는바 와 같이 객체 생성이 가능하다.

  • 이러한 객체 생성에서 int len부분은 사실 굳이 배열의 길이를 결정하기 위해 템플릿 매개변수에 정수를 전달하는 것보단
    생성자를 이용해도 되긴하다.
  • 하지만, SimpleClass<int, 5>SimpleClass<int, 7>을 비교하면, 두 class는 다른 형(type)이기 때문에 이와같이 배열 클래스 객체를 만들면 길이가 다른 두 배열 객체간의 대입은 허용되지 않는다!.
  • 따라서, 위 예제의 경우, 길이가 다른 두 배열 객체간의 개입 및 복사에 대한 부분을 신경 쓰지않아도 된다. 길이만 다르면 알아서 컴파일 에러로 IDE에서 빨간줄이 쫙 그어질 것이다. 만약 생성자를 통해서 배열의 길이를 결정하게 했다면, 길이가 같은 배열에 대해서만 대입을 허용하기 위해서 추가적인 코드의 삽입이 불가피하며, 이러한 추가적인 코드는 대입 및 복사의 과정에서 CPU가 수행해야 할 일을 늘리는 결과로 이어진다.

템플릿 매개변수는 디폴트 값 지정도 가능하다.

template <class T1=int, int len=7>// 이런식으로 Default value 지정!
class SimpleClass{
private:
	T arr[len];
public:
	T& operator[] (int idx){
    	return arr[idx];
    }
    
};

int main(void){
	SimpleClass<> arr;// arr의 T = int, len = 7 로 기본값이 넣어진다. 이떄 <>마크는 내부를 비워둘지언정 항상 있어야한다.
}

14-4. 템플릿과 static

함수 템플릿과 static 지역변수

template <class T>
void ShowstaticValue(void){
	static T num = 0;
    num+=1;
    cout << num << " ";
}

int main(void){
	ShowStaticValue<int>();
    ShowStaticValue<long>();
    return 0;
}

위와 같이 함수 템플릿 내에 지역변수 num을 static으로 선언한다. 그럼 컴파일러는 함수 템플릿 기반으로 아래와 같은 템플릿 함수를 만든다.


void ShowstaticValue<int>(void){
	static T num = 0;
    num+=1;
    cout << num << " ";
}
void ShowstaticValue<long>(void){
	static T num = 0;
    num+=1;
    cout << num << " ";
}

이때, static 지역변수가 템플릿 함수 별로 각각 존재하게 되어, 해당 타입에 맞는 static 지역변수를 부르게 된다.

클래스 템플릿과 static 멤버변수

static 멤버변수는 변수가 선언된 클래스의 객체간 공유가 가능한 변수이다. 따라서 아래와 같은 클래스 템플릿이 정의되면

template <class T>
class SimpleClass{
private:
	static T mem;
public:
	void AddMem(T num) {mem+=num;}
    void ShowMem(){cout << mem << endl;}
    
};
template<class T>
T SimpleClass<T>::mem=0;//템플릿 기반의 static 멤버 초기화 문장;

int main(void){
	SimpleClass<int> obj1;
    SimpleClass<long> obj2;
    return 0;
}

컴파일러에 의해서 아래와 같이 템플릿 클래스들이 생성된다.

class SimpleClass<int>{
private:
	static int mem;
public:
	void AddMem(int num) {mem+=num;}
    void ShowMem(){cout << mem << endl;}
    
};
int SimpleClass<int>::mem=0;//템플릿 기반의 static 멤버 초기화 문장;

class SimpleClass<long>{
private:
	static long mem;
public:
	void AddMem(long num) {mem+=num;}
    void ShowMem(){cout << mem << endl;}
    
};

long SimpleClass<long>::mem=0;//템플릿 기반의 static 멤버 초기화 문장;

템플릿 static 멤버변수 초기화의 특수화

방금 보였던 예제에서 T SimpleClass<T>::mem=0; 템플릿 기반의 static 멤버 초기화 문장은 모든 typemem0으로만 초기화되게 하였다. 하지만, 만약 long이나 double에는 4나 1.6 등을 넣어 초기화 시켜주고 싶다면 어찌해야하는가?
답은 초기화의 특수화에 있다.

  • 초기화문에 대해 특수하를 하자. 특수화는 함수 템플릿 또는 클래스 템플릿만을 대상으로 진행할 수 있는 것이 아니다.
template<class T>
T SimpleClass<T>::mem=0;//템플릿 기반의 static 멤버 초기화 문장;
____위를 아래와 같이 특수화 시킬 수 있다.____
template<>
long SimpleClass<long>::mem=5;
profile
언제나 감사하며 살자!

0개의 댓글