C++ Template 의 inner class 로 type 선언 하기
주의 사항
이 글은 예전 블로그에서 옮겨온 오래 된 글입니다. 현재 상황과는 다를 수 있으며, 잘못 된 정보가 있을 수 있습니다.
정성태님의 홈페이지를 정독하던중 오랫만에 C++ 관련 글이 하나 올라 왔길래 확인해 보았습니다. 바로 g++에서 inner 클래스를 사용한 템플릿이 제대로 선언 되지 않는다는 문제인데요, 코드는 아래와 같습니다(조금 다릅니다. 원본에 오타가 있어서 좀 고쳣습니다)
원본 : http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&pageno=0&detail=1&wid=1791
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <vector>
#include <map>
typedef char BYTE;
typedef int _int;
typedef std::vector<BYTE> _byteArrayHolder;
typedef long _long;
template <class T, class V>
class KeepAliveReceiver
{
};
template<class Receiver, class ErrorAction, _int MAX_CONTENT_SIZE = 8192>
class MultiPartByteArrayReceiver : public KeepAliveReceiver< MultiPartByteArrayReceiver<Receiver, ErrorAction>, ErrorAction>
{
class MultiPartByteArray
{
public:
_int key;
std::vector<BYTE> byteHolders;
_long totalSize;
public:
MultiPartByteArray(_int _key) : key(_key), byteHolders(), totalSize(0)
{
}
void AddBytes(_byteArrayHolder bytes)
{
totalSize += bytes.size();
}
};
typedef KeepAliveReceiver< MultiPartByteArrayReceiver<Receiver, ErrorAction, MAX_CONTENT_SIZE>, ErrorAction> Super;
typedef MultiPartByteArrayReceiver<Receiver, ErrorAction, MAX_CONTENT_SIZE> This;
public:
typedef std::map<_int, MultiPartByteArray> MultiPartBytesMap;
MultiPartBytesMap receivedMultiPartedBytes;
public:
MultiPartByteArrayReceiver() : Super(), receivedMultiPartedBytes()
{}
void Test()
{
MultiPartByteArray a(1);
std::map<_int, MultiPartByteArray>::iterator iter = receivedMultiPartedBytes.find(1); //컴파일 오류
}
};
int main()
{
std::cout << "Hello World" << std::endl;
MultiPartByteArrayReceiver<int, int> t;
t.Test();
return 0;
}
바로 위와 같은 코드인데, 이는 template 이 완전히 생성 되기 전에, 그 템플릿에 의존하는 type을 인식할 수 없기 때문에 발생합니다 (이런 경우는 템플릿 클래스가 부모 템플릿의 함수를 호출한다거나 할때도 발생합니다)
VC++은 그냥 적당히 알아서 (…) 인식해서 넘어 가는데 이걸 오류로 처리하는 컴파일러도 있습니다. 뭐 만드는사람 취향문제겟지만.
이 문제의 해결법은 바로 type을 인식하지 못하는 것이니 이게 template의 type 명을 나타낸다고 알려주는겁니다. 바로 typename 키워드를 쓰는것인데 그럼 아래와 같게 됩니다
1
typename std::map<_int, MultiPartByteArray>::iterator iter = receivedMultiPartedBytes.find(1); //컴파일 오류
이렇게 하면 뒤의 템플릿 선언문을 타입으로 인식하여 정상적으로 컴파일 됩니다. 물론 VC에서도 마찬가지입니다. 또 템플릿을 선언 할 때 처럼 class 키워드를 써도 OK 입니다. 전 typename 키워드가 헤깔리지 않아 선호하는 편이지만요
PS. 사실 이 모든 문법적 지저분함을 해결하는 마법의 키워드가 C++에 있으니…
그냥 auto 쓰면 됩니다 (…) C++11에서 추가된 auto와 decltype 의 타입추론 시스템은 템플릿을 정말 간단하게 만들어주는 축복이지요