C / C++,  Programming

[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.cchistogram.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

  1. https://stackoverflow.com/questions/8752837/undefined-reference-to-template-class-constructor

Leave a Reply

Your email address will not be published. Required fields are marked *