[C++] 템플릿(Template)은 헤더파일과 구현부 파일을 나누면 안 된다. (Error LNK 2019)

2022. 7. 19. 15:46Trouble Shootings

 

 

C++ 템플릿(Template) 공부를 하려고 예제 문제를 보면서 타이핑 해보고 있었습니다.

그런데, LNK 2019 오류가 저를 반겨줬습니다.

 

 

 

링킹(Linking)과 관련된 오류 같더군요. 저는 라이브러리 파일을 추가한 적도 없는데 말이죠.

무엇이 문제일까 고민하여 오류 코드를 구글링 해봤습니다. 다행히 저보다 먼저 고생하셔서 해결한 사례를 적어 놓으신 분이 있더라구요. 이런 분들이 저 같은 코린이에게는 구세주입니다.

 

 

문제는 헤더 파일과 구현 파일 분리였다.

결론부터 말하자면, 템플릿(Template)을 사용할 때 선언과 정의를 헤더 파일과 구현 파일로 분리한 것이 문제였습니다.

원래라면 헤더 파일에 선언을, 구현 파일에 구현부를 작성하는 게 일반적입니다.

관리하기가 수월할 뿐더러, 선언을 통해 미리 컴파일러에게 알려줘야 문법 체크나 최적화 작업을 진행할 수 있기 때문이죠.

잘 정리한 블로그가 있어 참고했습니다.

 

 

헤더 파일과 구현 파일의 분리가 필요한 이유
  • 컴파일러는 선언을 먼저 해줘야 다른 파일들의 내용을 확인할 수 있다.
  • 미리 선언된 내용이 없다면, 컴파일러는 해당 함수가 존재하는지 알 턱이 없다.
  • 이런 상황에 컴파일을 진행하다가 갑자기 듣도 보도 못한 함수가 나오면 에러를 발생시키는 것
  • 이러한 이유로 선언 내용들로만 담긴 헤더 파일을 통해 컴파일러에게 알려주는 것
  • 허나, 만약 헤더 파일에 구현부까지 모두 있다면 전처리 과정에서 #include하는 모든 부분들에 대해 컴파일 시간이 늘고, obj 파일 용량도 늘어나게 된다.
  • 그렇기 때문에 선언부와 구현부 파일을 각각 분리해주는 것

 

 

보통은 위와 같은 이유로 헤더 파일과 구현 파일을 분리하여 작업하는데, 템플릿(Template) 코드는 컴파일러가 컴파일 타임에 선언부만 봐서는 타입을 알 수가 없습니다.

구현 파일에 정의되어 있다고 하더라도 object 파일을 만드는 과정에서 헤더 파일에 선언되어 있는 해당 함수들은 제외되게 됩니다. 이런 이유 때문에 링크 과정에서 해당 함수를 찾지 못하는 것이었습니다. (참고 블로그)

 

따라서, 템플릿을 사용할 때는 헤더 파일과 구현 파일을 분리하지 말고, 헤더 파일에 구현부를 같이 선언해주어야 합니다.

/* Utils.h */
#pragma once

namespace utils {
	template <typename T>
	class Vector {
	private:
		T* data;
		int capacity;
		int length;
	public:
		Vector(int n = 1) : data(new T[n]), capacity(n), length(0) {}
		~Vector();
		void push_back(T element);
		void remove(int index);
		int size() { ... }
		T operator[](int index) { ... }
	};

	template <typename T>
	Vector<T>::~Vector() {
            ...
	}

	template <typename T>
	void Vector<T>::push_back(T element) {
            ...
    }

	template <typename T>
	void Vector<T>::remove(int index) {
            ...
	}
}

 

위와 같이 적는 게 맞나 모르겠네요. 인라인(inline)처럼 작성하라는 의미인지, 위처럼 작성한라는 의미인지...

일단 위 코드는 정상적으로 잘 돌아갔습니다.

 

 

 

 

 

 

728x90
반응형