2009-07-10 7 views
36

이것은 지난 1 시간 반 동안 나를 미치게했습니다. 나는 그것이 작은 것이지만 무엇이 잘못되었는지를 알 수 없다는 것을 안다. (물론 비오는 금요일 오후인데 도움이되지 않는다.)템플릿 메서드에 대한 정의되지 않은 참조 오류

나는 파일에서 읽을 구성 매개 변수를 개최하고 내 프로그램에서 액세스 할 수있게된다 다음 클래스를 정의 : 방법 convert()

template <typename T> 
T VAConfig::convert(const std::string& value) 
{ 
    T t; 
    std::istringstream iss(value, std::istringstream::in); 
    iss >> t; 
    return t; 
} 
VAConfig.cpp에 정의되어

class VAConfig { 
    friend std::ostream& operator<<(std::ostream& lhs, const VAConfig& rhs); 

private: 
    VAConfig(); 
    static std::string  configFilename; 
    static VAConfig*  pConfigInstance; 
    static TiXmlDocument* pXmlDoc; 
    std::map<std::string, std::string> valueHash; 

public: 
    static VAConfig* getInstance(); 
    static void setConfigFileName(std::string& filename) { configFilename = filename; } 
    virtual ~VAConfig(); 

    void readParameterSet(std::string parameterGroupName); 
    template<typename T> T readParameter(const std::string parameterName); 
    template<typename T> T convert(const std::string& value); 
}; 

모두 매우 간단합니다. 하지만 내 메인 프로그램에서 테스트 할 때

int y = parameters->convert<int>("5"); 

나는 undefined reference to 'int VAConfig::convert<int>...' 컴파일 오류가 발생합니다. 동부 표준시 readParameter().

많은 템플릿 자습서를 보았지만이를 파악하지 못했습니다. 어떤 아이디어?

+2

1 시간 반이 그렇게 나쁘지 않아 ... 어제 3시 간 나를 죽였다. –

답변

55

템플릿 기반 코드 구현이 .cpp 파일 않을 것입니다 : 다음 .cpp은 컴파일러가 당신이 템플릿 오브젝트 코드를 생성 할 explicit instantiation을 사용하지 않는 (를 호출하는 코드를보고 함과 동시에 그들을 볼 수있다, 그러나 경우에도 사용할 잘못된 파일 형식).

템플리트 멤버 함수를 사용할 때마다 구현을 헤더 파일 또는 VAConfig.t.hpp과 같은 파일로 이동 한 다음 #include "VAConfig.t.hpp"으로 이동해야합니다.

+0

감사합니다. 세스 (Seth)와 도미니크 (Dominic) 님, 구현을 헤더 파일로 옮겼습니다. 내가 읽은 튜토리얼에서 언급 한이 부분을 본 적이 없다. 그렇다면 컴파일러는 호출하는 코드를 볼 때 구현을보아야하는 이유는 무엇입니까? 즉 템플릿 화 된 기능을이 점에서 고유하게 만드는 이유는 무엇입니까? – recipriversexclusion

+2

컴파일러는 템플릿을 인스턴스화 할 때 전체 템플릿 정의를 사용할 수 있어야하므로 템플릿 매개 변수를 대체하고 평가할 수 있습니다. 컴파일러에서 지원하는 경우 템플릿을 "extern"으로 선언하고 다른 멤버와 마찬가지로 사용할 수 있습니다 (추가 링크 타임 작업은 필요함). GCC는이를 확장으로 지원합니다. 그것은 C++ 0x 표준의 일부가 될 것입니다. – greyfade

+0

템플릿을 멀리 유지하는 기술, 즉 템플릿 특수화를 선언하는 기술이 있습니다. -1 for "should never" –

9

변형 된 메서드 (convert 및 readParameter)의 구현을 헤더 파일로 옮기면 작동합니다.

컴파일러는 인스턴스화 된 지점에서 템플릿 함수의 구현에 액세스 할 수 있어야합니다.

5

템플릿 메서드는 메서드에 대한 템플릿 일뿐입니다. 템플리트 인수는 메소드가 "인스턴스화 된"곳에 채워집니다.

템플릿 메서드 선언에 만족하고 '템플릿 컴파일'단계를 통해 템플릿 메서드의 필요한 모든 인스턴스를 컴파일 할 수 있어야합니다.

Microsoft의 VC에는 해당되지 않습니다. 하지만 유닉스에 관한 동료 중얼 거리는 소리가 들렸다.

대부분의 컴파일러는 소스 코드에서 사용되는 템플릿 메서드를 요청시 인스턴스화합니다. 메소드를 인스턴스화하려면 컴파일러가 템플릿 함수 본문을 '확인'해야합니다. 그래서 시체가 가장 자주 헤더 파일이나 예를 들어 .h 파일의 마지막 줄에 포함 된 .h.cpp 파일.

+0

설명하는 것은 "extern template"입니다. 이것은 C++ 표준의 다음 버전에 포함되어 있으며 오랫동안 (확장으로서) GCC에 의해 지원되었습니다. Visual C++는 다음 릴리스의 최신 베타 버전에서이를 지원해야합니다. – greyfade

+0

@greyfade : 고마워! – xtofl

+0

.h.cpp 또는 .hpp? – Naveen