[C++] undefined reference to template
C++ programming을 하다보면 build 중 다음과 같은 error를 쉽게 겪을 수 있다.
test.cc:(.text+0x162): undefined reference to `Histogram<unsigned int>::setVal(unsigned int)' collect2: error: ld returned 1 exit status
기본적으로 C++에선 source file에선 template
형태의 함수를 가질 수 없다고 한다.
Example
// histogram.h #ifndef _HISTOGRAM_H_ #define _HISTOGRAM_H_ #include <iostream> #include <vector> template <typename T> class Histogram { struct Hist_Info { T val; unsigned cycle; }; public: Histogram(unsigned &cycle): _cycle(cycle) { } ~Histogram() {} void setVal(T val); void printHistogram(void); private: unsigned &_cycle; std::vector<Hist_Info> _list; }; #endif /* _HISTOGRAM_H_*/
// histogram.cc template <typename T> void Histogram<T>::setVal (T val) { _cycle++; Hist_Info hi; hi.cycle = _cycle; hi.val = val; if (_list.empty()) { _list.push_back(hi); return; } // Check the data is same with previous data Hist_Info latestInfo = _list.front(); if (latestInfo.val != val) { _list.push_back(hi); } } template <typename T> void Histogram<T>::printHistogram (void) { for (auto iter=_list.begin(); iter<_list.end(); iter++) { std::cout << "[" << iter->cycle << "] Value=" << iter->val << std::endl; } }
위와 같이 header와 source file을 분리해서 사용하고자 했는데, linking time에서 error가 발생했다.
원인
이런 error가 발생한 이유는 compiler가 build 할 때 template class의 type이 어떤게 사용될지 모르기 때문이다.
만약 test.cc
라는 파일에서 해당 class를 호출해서 사용한다고 했을 때, histogram.h
를 including해서 사용할텐데, 어떤 type의 instance를 생성할지를 알고 test.o를 만들 것이다. 그러나 histogram.cc
를 histogram.o
로 만들 때는 어떤 type을 사용할지는 알 방법이 없다. 따라서 hint를 주거나, 에초에 test.cc
를 compile 할 때 어떤 타입의 instance를 사용될지 알 수 있도록 header에 해당 template function을 기술해야한다.
1. Copy the code into the relevant header file
쉽게 header file에 source code에 기술된 내용을 옮기면 된다.
#ifndef _HISTOGRAM_H_ #define _HISTOGRAM_H_ #include <iostream> #include <vector> template <typename T> class Histogram { struct Hist_Info { T val; unsigned cycle; }; public: Histogram(unsigned &cycle): _cycle(cycle) { } ~Histogram() {} void setVal(T val); void printHistogram(void); private: unsigned &_cycle; std::vector<Hist_Info> _list; }; template <typename T> void Histogram<T>::setVal (T val) { _cycle++; Hist_Info hi; hi.cycle = _cycle; hi.val = val; if (_list.empty()) { _list.push_back(hi); return; } // Check the data is same with previous data Hist_Info latestInfo = _list.front(); if (latestInfo.val != val) { _list.push_back(hi); } } template <typename T> void Histogram<T>::printHistogram (void) { for (auto iter=_list.begin(); iter<_list.end(); iter++) { std::cout << "[" << iter->cycle << "] Value=" << iter->val << std::endl; } } #endif /* _HISTOGRAM_H_*/
2. Explicitly instantiate the template
histogram.cc 마지막에 다음과 같이 type 명시를 해준다.
template class Histogram <unsigned>;
Reference
- https://stackoverflow.com/questions/8752837/undefined-reference-to-template-class-constructor