C++ Chapter 13.5 : 클래스 템플릿 특수화
카테고리: Cpp
태그: Cpp Programming
인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!
chapter 13. 템플릿 : 클래스 템플릿 특수화
특수화
: 템플릿에서 특정 타입에 대해서 다른 실행 처리를 하고 싶을 때 그 타입에 대해서만 특수화.
🔔 클래스 템플릿 특수화
template<>
class A<char>
{
};
T
를 구체화 하니까T
를 제외한typename<>
만 써준 후 클래스 이름 옆에<특수화 할 타입>
를 명시해준다.
- 해당 클래스로 객체를 생성할 때 char 타입으로 구체화할 때만 위 클래스로 구체화된다.
#include <iostream>
using namespace std;
template<typename T>
class A
{
public:
A(const T& input)
{}
void doSomething()
{
cout << typeid(T).name() << endl;
}
void test()
{}
};
template<>
class A<char>
{
public:
A(const char& input)
{}
void doSomething()
{
cout << "Char type specialization" << endl;
}
};
int main()
{
A<int> a_int(1);
A<double> a_double(3.14);
A<char> a_char('a');
a_int.doSomething();
a_double.doSomething();
a_char.doSomething();
a_char.test(); // ❌에러❌
return 0;
}
- ⭐
char
타입으로 구체화 될 땐 다른 타입들로 구체화될 때와 다르게test()
멤버 함수가 없는 것이나 마찬가지다.char
타입으로 구체화 될 땐 첫번째 클래스 템플릿으로 구체화되는게 아니라 아래 두번째 클래스 템플릿으로 구체화되기 때문이다.template<> class A<char> { public: A(const char& input) {} void doSomething() { cout << "Char type specialization" << endl; } };
A<char> a_char('a'); a_char.test(); // ❌에러❌
char
타입으로 구체화 될 때만 위 클래스로 객체를 찍어내기 때문에 생성자도 따로 정의해주어야 한다.- 그렇지 않으면 그냥 빈 내용의 디폴트 생성자를 컴파일러가 만들어 호출함!
- 원래 생성자 정의가 없었다면 상관 없지만 원래 클래스 템플릿에 생성자가 있었다면 정의해주자.
- C++ 17 부터는 생성자 매개변수로 들어가는 인수로
T
타입을 알 수 있는 경우<구체화타입>
을 생략할 수 있다.A a_int(1); // 👉 int 로 구체화 A a_double(3.14); // 👉 double 로 구체화 A a_char('a'); // 👉 char 로 구체화
🔔 응용
크기 8 의 배열을 멤버로 가지는 클래스를 만든다고 할 때, 어차피 bool은 1bit로 표현할 수 있으므로 특별히 bool 타입일때만 1 byte = 8 bit 크기인 char 타입의 데이터 1 개를 마치 8 개의 bit 배열인 것처럼 구현하자.
#include <iostream>
using namespace std;
template<typename T>
class Storage8
{
private:
T m_array[8];
public:
void set(int index, const T &value)
{
m_array[index] = value;
}
const T& get(int index)
{
return m_array[index];
}
};
template<>
class Storage8<bool>
{
private:
unsigned char m_data;
public:
Storage8()
: m_data(0)
{}
void set(int index, bool value)
{
unsigned char mask = 1 << index;
if (value)
m_data |= mask;
else
m_data &= ~mask;
}
bool get(int index)
{
unsigned char mask = 1 << index;
return (m_data & mask) != 0;
}
};
int main()
{
Storage8<int> intStorage;
for (int count = 0; count < 8; ++count)
intStorage.set(count, count);
for (int count = 0; count < 8; ++count)
cout << intStorage.get(count) << " ";
cout << " Sizeof Storage8<int> " << sizeof(Storage8<int>) << endl;
Storage8<bool> boolStorage;
for (int count = 0; count < 8; ++count)
boolStorage.set(count, count & 3);
for (int count = 0; count < 8; ++count)
cout << boolStorage.get(count) << " ";
cout << " Sizeof Storage8<bool> " << sizeof(Storage8<bool>) << endl;
return 0;
}
bool
타입일 때 클래스 템플릿 특수화template<> class Storage8<bool> { private: unsigned char m_data; public: Storage8() : m_data(0) {} void set(int index, bool value) { unsigned char mask = 1 << index; if (value) m_data |= mask; else m_data &= ~mask; } bool get(int index) { unsigned char mask = 1 << index; return (m_data & mask) != 0; } };
bool
타입으로 구체화할 때만- 배열을 쓰지 않고
unsigned char
타입의 데이터 m_data 하나를 싸용한다.- 이 1byte = 8bit로 8가지의 ture or false를 표현할 것.
- 특별히 생성자 있다!
- m_data 를 0 으로 초기화함.
-
set(int index, bool value) index 번째 자리에 value 값을 set한다.
- 예를들어 index가 5 라면
unsigend char m_data
의 5 번째 자리에bool value
의 결과인 0 or 1 을 저장해야 하기 때문에 00000001 을 5 만큼 왼쪽 shift 연산 해주고 이를mask
에 대입.- mask =
1 << 5
👉00100000
- mask =
bool value
가 True 라면unsigend char m_data
의 5번째 자리를 1로 만들어주어야 한다.m_data |= mask
👉m_data |= 00100000
bool value
가 False 라면unsigend char m_data
의 5번째 자리를 0으로 만들어주어야 한다.m_data &= ~mask
👉m_data |= 00100000
- 예를들어 index가 5 라면
-
get(int index) index 번째 자리의 value 값을 get 리턴한다.
- 예를들어 index가 4 라면
unsigend char m_data
의 4 번째 자리의 bit 값이 1 이면 True 리턴, 0 이면 False 리턴 식으로 구현해야 한다.- 00000001 을 4 만큼 왼쪽 shift 연산 해준다.
- mask =
1 << 4
👉00010000
mask
는 4번째 자리만 1인 비트가 된다.m_data & mask
결과가mask = 00010000
이면, 즉 0이 아니면 True 리턴m_data & mask
결과가00000000
이면, 즉 0이면 False 리턴
- 예를들어 index가 4 라면
- 배열을 쓰지 않고
- 출력
0 1 2 3 4 5 6 7 Sizeof Storage8<int> 32 0 1 1 1 0 1 1 1 Sizeof Storage8<bool> 1
- int 로 구체화 되었을 땐 8 크기의 int 배열 멤버로 8 * 4byte = 32 byte 로 크키가 32로 나온 것을 볼 수 있다.
- bool로 구체화 되었을 땐 char 멤버 하나로 1 byte 크기로 크기가 1 이 나온 것을 알 수 있다.
- bool 타입이 구체화가 되지 않고 그냥 bool도 8 크기의 bool 배열 멤버를 사용했다면 8 이 나왔을 것이다.
- bool 원래는 1 byte니까. 1bit로 표현할 수 있긴 하지만!
- bool 타입이 구체화가 되지 않고 그냥 bool도 8 크기의 bool 배열 멤버를 사용했다면 8 이 나왔을 것이다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기