일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- dart 언어
- Data Structure
- HTML
- 다트 언어
- c언어
- C# delegate
- c#
- c# 추상 클래스
- 깃
- Python
- Flutter
- Algorithm
- 구조체
- c# winform
- git
- C++
- 도커
- Houdini
- c# 윈폼
- vim
- Unity
- docker
- jupyter lab
- 플러터
- github
- 유니티
- C언어 포인터
- jupyter
- gitlab
- 포인터
- Today
- Total
nomad-programmer
[Programming/C++] 템플릿과 static 본문
함수 템플릿과 static 지역 변수
template <typename T>
void ShowStaticValue(void) {
static T num = 0;
num += 1;
cout << num << " ";
}
함수 템플릿 내에 지역변수 num이 static으로 선언되었다. 그런데 위의 '함수 템플릿'을 기반으로 컴파일러는 다음과 같이 '템플릿 함수'들을 만들어 낸다.
void ShowStaticValue<int> (void) {
static int num = 0;
num += 1;
cout << num << " ";
}
void ShowStaticValue<double> (void) {
static double num = 0;
num += 1;
cout << num << " ";
}
따라서 static 지역변수도 템플릿 함수 별로 각각 존재하게 된다.
#include <iostream>
#pragma warning(disable: 4996)
using std::cout;
using std::cin;
using std::endl;
template <typename T>
void ShowStaticValue(void) {
static T num = 0;
num += 1;
cout << num << " ";
}
int main(const int argc, const char* const argv[]) {
ShowStaticValue<int>();
ShowStaticValue<int>();
ShowStaticValue<int>();
cout << endl;
ShowStaticValue<long>();
ShowStaticValue<long>();
ShowStaticValue<long>();
cout << endl;
ShowStaticValue<double>();
ShowStaticValue<double>();
ShowStaticValue<double>();
return 0;
}
/* 결과
1 2 3
1 2 3
1 2 3
*/
컴파일러에 의해서 만들어진 템플릿 함수 별로 static 지역변수가 유지됨을 알 수 있다.
클래스 템플릿과 static 멤버변수
static 멤버변수는 변수가 선언된 클래스의 객체간 공유가 가능한 변수이다.
template <typename T>
class SimpleStatic {
private:
static T mem;
...
};
template <typename T>
T SimpleStatic<T>::mem = 0;
...
따라서 위와 같이 클래스 템플릿이 정의되면 컴파일러에 의해서 다음과 같이 템플릿 클래스들이 생성되어 템플릿 클래스 별로 static 멤버변수를 유지하게 된다.
class SimpleStatic<int> {
private:
static int mem;
...
};
int SimpleStatic<int>::mem = 0;
...
class SimpleStatic<double> {
private:
static double mem;
...
};
double SimpleStatic<double>::mem = 0;
...
다음의 예제를 살펴보자.
#include <iostream>
#pragma warning(disable: 4996)
using std::cout;
using std::cin;
using std::endl;
template <typename T>
class SimpleStaticMem {
private:
static T mem;
public:
void AddMem(int num) {
mem += num;
}
void ShowMem(void) const {
cout << mem << endl;
}
};
// static 멤버의 초기화 문장
template <typename T>
T SimpleStaticMem<T>::mem = 0;
int main(const int argc, const char* const argv[]) {
SimpleStaticMem<int> obj1;
SimpleStaticMem<int> obj2;
obj1.AddMem(2);
obj2.AddMem(3);
obj1.ShowMem();
SimpleStaticMem<long> obj3;
SimpleStaticMem<long> obj4;
obj3.AddMem(100);
obj4.ShowMem();
return 0;
}
/* 결과
5
100
*/
template <typename T>와 template <>
언제 template <typename T> 선언이 필요한가?
언제 template <> 선언이 필요한가?
템플릿 관련 정의에는 template <typename T> 또는 template <>와 같은 선언을 둬서, 템플릿의 일부 또는 전부를 정의하고 있다는 사실을 컴파일러에게 알려야 한다.
다음의 경우 템플릿 정의에 T가 등장하므로 template <typename T>의 선언을 통해, T가 의미하는 바를 알려야 한다.
template <typename T>
class Simple {
public:
T Simple(T num) { ... }
};
다음은 클래스 템플릿을 int형에 대해서 특수화 한 결과이다.
template <>
class Simple<int> {
public:
int Simple(int num) { ... }
};
이 정의의 핵심은 <int>이다. 그런데 이 역시 템플릿 관련 정의이기 때문에, 이러한 사실을 알리기 위한 선언이 필요하다. 하지만 이 정의에서는 T라는 문자가 등장하지 않으니, template <>을 선언하는 것이다.
즉, 정의 부분에 T가 존재하면 T에 대한 설명을 위해서 <typename T>의 형태로 덧붙이면 되고, T가 존재하지 않으면 <>의 형태로 간단하게 선언하면 된다.
템플릿 static 멤버변수 초기화의 특수화
다음과 같은 형태로 static멤버를 초기화하였다. 때문에 모든 mem은 0으로 초기화된다.
template <typename T>
T SimpleStaticMem<T>::mem = 0;
그런데 long 타입의 static 멤버변수는 0이 아닌 다른 값으로 초기화하려면 어떻게 해야 할까? 이 때 필요한 것이 멤버변수 초기화의 특수화이다.
초기화문에 대해서 특수화를 진행하면 된다. 특수화는 함수 템플릿 또는 클래스 템플릿만을 대상으로 진행할 수 있는 것이 아니다.
클래스 템플릿 정의의 일부인 초기화문을 대상으로도 진행이 가능하다. 다양한 특수화와 마찬가지로 T를 대신해서 특수화하고자 하는 자료형의 이름을 삽입하면 된다.
template <>
long SimpleStaticMem<long>::mem = 5;
T를 long으로 바꾼 결과로 T가 모두 사라졌다. 그래서 <typename T>를 대신해서 <>을 사용해 템플릿 정의의 일부임을 알려야 한다.
#include <iostream>
#pragma warning(disable: 4996)
using std::cout;
using std::cin;
using std::endl;
template <typename T>
class SimpleStaticMem {
private:
static T mem;
public:
void AddMem(int num) {
mem += num;
}
void ShowMem(void) const {
cout << mem << endl;
}
};
// static 멤버의 초기화 문장
template <typename T>
T SimpleStaticMem<T>::mem = 0;
// static 멤버변수에 특수화 진행
template <>
long SimpleStaticMem<long>::mem = 5;
int main(const int argc, const char* const argv[]) {
SimpleStaticMem<int> obj1;
SimpleStaticMem<int> obj2;
obj1.AddMem(2);
obj2.AddMem(3);
obj1.ShowMem();
SimpleStaticMem<long> obj3;
SimpleStaticMem<long> obj4;
obj3.AddMem(100);
obj4.ShowMem();
return 0;
}
/* 결과
5
105
*/
'Programming > C++' 카테고리의 다른 글
[Programming/C++] 정수 값을 2진수로 출력하는 방법 (bitset) (0) | 2023.01.08 |
---|---|
[Programming/C++] C++에서의 형 변환 연산 (0) | 2021.02.08 |
[Programming/C++] 템플릿 인자 (0) | 2021.02.07 |
[Programming/C++] 클래스 템플릿의 특수화(Class Template Specialization) (0) | 2021.02.07 |
[Programming/C++] 클래스 템플릿(Class Template) (0) | 2021.02.07 |