G++ - 템플릿 클래스의 iterator 코드 사용에서 발생하는 컴파일 오류
G++ 컴파일러로 다음의 코드를 컴파일 하면,
#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 MuliPartByteArray
    {
        _int key;
        std::vector<BYTE> byteHolders;
        _long totalSize;
    public:
        MuliPartByteArray(_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, MuliPartByteArray>  MultiPartBytesMap;
    MultiPartBytesMap receivedMultiPartedBytes;
public:
    MultiPartByteArrayReceiver() : Super(), receivedMultiPartedBytes()
    {}
    void Test()
    {
        std::map<_int, MultiPartByteArray>::iterator iter = receivedMultiPartedBytes.find(1); // 컴파일 오류
    }
};
using namespace std;
int main()
{
    cout << "Hello World" << endl;
    MultiPartByteArrayReceiver<int, int> t;
    size_t size = t.receivedMultiPartedBytes.size();
   return 0;
}
이런 컴파일 오류가 발생합니다.
main.cpp: In member function void MultiPartByteArrayReceiver<Receiver, ErrorAction, MAX_CONTENT_SIZE>::Test():
main.cpp:60:28: error: MultiPartByteArray was not declared in this scope
             std::map<_int, MultiPartByteArray>::iterator iter = receivedMultiPartedBytes.find(1);
                            ^
main.cpp:60:46: error: template argument 2 is invalid
             std::map<_int, MultiPartByteArray>::iterator iter = receivedMultiPartedBytes.find(1);
                                              ^
main.cpp:60:46: error: template argument 4 is invalid
main.cpp:60:58: error: expected initializer before iter
             std::map<_int, MultiPartByteArray>::iterator iter = receivedMultiPartedBytes.find(1);
                                                          ^
아~~~ 이 현란한 C++ template 사용이여~~~~!
위의 컴파일 오류를 보여준 직장 동료의 우회 방법은 MultiPartByteArrayReceiver 클래스 내에 inner 클래스로 정의된 MuliPartByteArray를 바깥으로 빼내는 것이었습니다.
#include <iostream>
#include <vector>
#include <map>
// ... [생략]...
class MuliPartByteArray
{
    // ... [생략]...
};
template<class Receiver, class ErrorAction, _int MAX_CONTENT_SIZE = 8192>
class MultiPartByteArrayReceiver : public KeepAliveReceiver< MultiPartByteArrayReceiver<Receiver, ErrorAction>, ErrorAction>
{
    // ... [생략]...
};
// ... [생략]...
그런데... 사실 inner 클래스는 이유가 있기 때문에 inner 클래스가 된 것인데 그것을 바깥으로 빼내는 것은 그리 바람직해 보이지 않았습니다. 제가 제시한 해결책은 클래스의 전방 선언이었는데, 다음과 같이 처리하는 것이었습니다.
#include <iostream>
#include <vector>
#include <map>
// ... [생략]...
class MuliPartByteArray;
template<class Receiver, class ErrorAction, _int MAX_CONTENT_SIZE = 8192>
class MultiPartByteArrayReceiver : public KeepAliveReceiver< MultiPartByteArrayReceiver<Receiver, ErrorAction>, ErrorAction>
{
    class MuliPartByteArray
    {
        // ... [생략]...
    };
    // ... [생략]...
};
// ... [생략]...
이렇게 해주면 컴파일이 잘 됩니다. 직장 동료가 이유를 물었지만... 허허허~~~ 어찌 그것을 제가 알 수 있겠습니까? 단지 과거에 C++ template과 잠시 싸워 온 일종의 감각으로 전방 선언이 효력이 있을 거라는 생각을 했을 뿐입니다. (혹시, 명확한 이유를 알고 계신 분이 있다면 덧글 좀~~~~ ^^)
참고로, 이 예제의 코드는 Visual C++ 2013에서는 전방 선언 필요없이도 잘 컴파일됩니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]