이 글에서는 C++에서 발생하는 "incomplete types" 에러를 이해하고 이를 해결하는 방법을 설명합니다.
문제상황
// main.cpp
#include <iostream>
#include "Container.h"
int main() {
Container<int> container;
container.addItem(10);
container.addItem(20);
std::cout << "Item count: " << container.size() << std::endl;
return 0;
}
// Container.h
#pragma once
#include <vector>
template <typename T>
class Container {
public:
void addItem(const T& item);
std::size_t size() const;
private:
std::vector<T> items;
};
// Container.cpp
#include "Container.h"
template <typename T>
void Container<T>::addItem(const T& item) {
items.push_back(item);
}
template <typename T>
std::size_t Container<T>::size() const {
return items.size();
}
위 코드는 Container라는 템플릿 클래스를 사용하여 여러 타입의 객체를 저장하는 컨테이너를 구현한 것입니다. 컨테이너에 아이템을 추가하고, 저장된 아이템의 개수를 확인하는 간단한 예제입니다.
에러로그 내용:
error LNK2019: unresolved external symbol "public: void __thiscall Container<int>::addItem(int const &)" (?addItem@?$Container@H@@QAEXABH@Z) referenced in function _main
error LNK2019: unresolved external symbol "public: unsigned int __thiscall Container<int>::size(void)const " (?size@?$Container@H@@QBEIXZ) referenced in function _main
원인분석
이 에러는 링커가 addItem와 size 멤버 함수를 찾지 못해서 발생하는 문제입니다. 이 문제를 이해하려면 템플릿의 컴파일 과정에 대해 이해해야 합니다.
C++ 템플릿은 컴파일 시점에 구체화(concretize)되며, 각 구체화된 템플릿 인스턴스는 별도의 코드를 생성합니다. 이 때문에 템플릿 함수의 정의는 헤더 파일에 위치해야 합니다. 하지만 위의 예제에서는 템플릿 클래스의 멤버 함수 정의가 별도의 .cpp 파일에 있습니다. 이로 인해 링커가 참조할 수 없는 상황이 발생한 것입니다.
에러 발생 원리는 다음과 같습니다.
- 컴파일러는 main.cpp와 Container.cpp 파일을 각각 컴파일합니다.
- main.cpp에서 Container를 인스턴스화하면서 addItem과 size 함수에 대한 정의를 찾으려고 시도합니다.
- 하지만, Container.cpp에서 정의한 addItem과 size 함수는 이미 컴파일된 객체 파일에 포함되어 있기 때문에, 링커는 이를 찾을 수 없습니다. 이로 인해 "unresolved external symbol" 에러가 발생합니다.
해결방법-템플릿 멤버 함수 정의를 헤더 파일로 이동
에러를 해결하기 위해서는 템플릿 멤버 함수의 정의를 Container.h 헤더 파일로 이동시켜야 합니다.
// Container.h
#pragma once
#include <vector>
template <typename T>
class Container {
public:
void addItem(const T& item);
std::size_t size() const;
private:
std::vector<T> items;
};
template <typename T>
void Container<T>::addItem(const T& item) {
items.push_back(item);
}
template <typename T>
std::size_t Container<T>::size() const {
return items.size();
}
Container.cpp 파일은 더 이상 필요하지 않으므로 삭제하시기 바랍니다.
해결된 코드의 작동 원리는 다음과 같습니다.
- 컴파일러는 main.cpp를 컴파일하면서 Container 인스턴스화를 시도합니다.
- 이제 템플릿 멤버 함수의 정의가 헤더 파일에 있으므로, 컴파일러는 이를 찾을 수 있습니다.
- 컴파일러가 addItem과 size 함수에 대한 정의를 찾으면 링커는 이를 올바르게 연결할 수 있습니다.
참고링크
728x90