강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

김동현님의 프로필 이미지
김동현

작성한 질문수

홍정모의 따라하며 배우는 C++

13.4 함수 템플릿 특수화

강의와 똑같이 진행했는데 링킹 에러가 발생합니다.

작성

·

23

1

main.cpp

#include <iostream>
#include "Storage.h"

using namespace std;

int main()
{
    Storage<int> nValue(5);
    Storage<double> dValue(6.7);

    nValue.print();
    dValue.print();
}

 

Storage.h

 

#pragma once

#include <iostream>

template <class T>
class Storage
{
private:
	T m_value;

public:
	Storage(T value)
	{
		m_value = value;
	}

	~Storage()
	{

	}

	void print()
	{
		std::cout << m_value << std::endl;
	}

};

 

Storage.cpp

#include "Storage.h"

template<>
void Storage<double>::print()
{
	std::cout << "Double Type ";
	std::cout << std::scientific << m_value << "\n";
}

 

현재 강의 중 8:03을 보고 있고요.

 

강의 중에서 영상을 봤을 땐 이렇게 하라고 교수님께서 말씀해주신듯 한데, 혹시 제가 뭘 잘못한게 있나요?

 

강의 상에서는 코드를 이렇게 작성한 경우, Specialization이 적용되지 않는 사례를 보여주시려고 하신듯 한데 저는 빌드가 되질 않습니다.

 

image.png

 

 

답변 2

0

안녕하세요? 질문&답변 도우미 durams입니다.

저도 이전에 강의를 수강했을 때에는 빌드가 되었던 코드였던것 같은데, 지금 해보니 빌드가 되질 않네요. 아마 Visual Studio가 업데이트하면서 링커에 더 엄격한 규칙이 적용된 것이 아닐까 싶습니다.

에러문을 보면 여러 cpp파일 (정확히는 여러 Translation Unit)에서 Storage<double>::print가 정의되어서 그렇다고 나옵니다.

  1. main.cpp에서 dValue.print()할 때 Storage<double>::print에 대한 정의 생성

  2. Storage.cpp에서 특수화를 통해 Storage<double>::print에 대한 정의 생성

이렇게 두 개의 정의가 존재해서 링킹 에러가 난다고 해석할 수 있습니다.

해결 방법으로는 강의에서 소개된 것과같이 헤더 파일에 정의를 포함시키는 것이 일반적입니다.

0

안녕하세요, 인프런 AI 인턴입니다. 김동현님.

현재 질문하신 내용과 관련하여, C++ 템플릿을 사용한 코드에서 발생할 수 있는 몇 가지 일반적인 문제들에 대해 설명드릴 수 있을 것 같습니다.

C++에서 템플릿 클래스의 특수화(Specialization)를 사용할 때, 그 정의를 .cpp 파일에 별도로 작성하면 링커 에러가 발생할 수 있습니다. 이는 템플릿의 특성 때문인데, 템플릿 함수와 클래스의 정의는 일반적으로 헤더 파일에 위치해야 컴파일러가 여러 파일을 컴파일할 때 각 인스턴스에 대한 코드 생성을 적절하게 수행할 수 있습니다.

귀하의 경우, Storage<double> 클래스의 print 함수 특수화를 Storage.cpp 파일에 작성했지만, 이 특수화를 헤더 파일(Storage.h)로 옮기는 것이 옳습니다. 모든 템플릿 정의를 헤더 파일로 옮겨보세요.

이에 대한 관련 논의를 다룬 StackOverflow의 답변을 참고하실 수 있습니다. 이 문서에서는 C++ 템플릿 특수화가 주로 헤더 파일에 정의되어야 하는 이유와 적절한 사용 방법을 다루고 있습니다.

문제를 해결하기 위해서는 아래와 같이 Storage<double>::print의 특수화를 Storage.h 파일로 다시 옮겨주세요.

// Storage.h

#pragma once

#include <iostream>

template <class T>
class Storage
{
private:
	T m_value;

public:
	Storage(T value)
	{
		m_value = value;
	}

	~Storage()
	{

	}

	void print()
	{
		std::cout << m_value << std::endl;
	}

};

// Make sure to move the specialization to the header file
template<>
void Storage<double>::print()
{
	std::cout << "Double Type ";
	std::cout << std::scientific << m_value << "\n";
}

이렇게 하면, 모든 컴파일러가 템플릿 특수화에 접근할 수 있게 되어 링커 에러를 방지할 수 있게 됩니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

김동현님의 프로필 이미지
김동현

작성한 질문수

질문하기