관리 메뉴

흐에에에에에엥

[C++] template 함수 사용법 - LNK2019 에러 본문

코딩/C++

[C++] template 함수 사용법 - LNK2019 에러

김미이이인서어어어억 2020. 10. 3. 04:04

안녕하세요
오늘은 제가 C++ 과제를 하다가 template 사용법을 까먹고 부끄러운 질문을 해서 잊지 않기 위해 적어보려고 합니다.

Error 해결


바로 여기에 있는 에러인데요
함수에서 참조할 수 없다고 뜨는걸 보니 include에서 잘못된 것으로 알고 있었습니다.
그래서 헤더 파일이 꼬였었나 헤더파일을 뒤적이다 도저히 알 수 없어서 구글 선생님께 여쭤봤는데 정답을 제가 찾지 못했습니다.
결국 학교 단체 톡방에 물어보니 3분만에 링크하나로 답변이 왔었더군요... https://devhoma.tistory.com/49 바로 여기서 LNK2019 에러 발생 시 확인 할 수 있는 문제들을 하나씩 체크하다보니
저는 template 함수를 구현할 때 정의(.h : 헤더파일) 과 구현  (.cpp : 씨피피파일?) 을 분리해서 작성한 것이 화근이 되었습니다... 과거에 날탱이처럼 template함수를 슥 보고 넘어간 것이 문제였습니다. 다음부터는 꼭 그러지 않겠다는 다짐하에 이렇게 글을 써봅니다.


Template 함수 작성법



Template 이란?

 ppt를 만들 때 제일 많이 사용되는 단어인데요, 일정한 형식의 틀 느낌을 생각하시면 될 것 같습니다. 흔히들 붕어빵과 붕어빵 틀을 얘기할 수 있습니다!

 우리는 붕어빵을 먹을 때 슈크림 붕어빵, 팥이 들어간 붕어빵, 혹은 누군가의 치즈 붕어빵(?) 같은 여러가지 붕어빵을 만들어서 먹을 수 있습니다. 붕어 모양의 틀에서 붕어모양의 빵을 찍어냈기에 우리는 붕어빵이라고 생각하는 것입니다. 만약 붕어빵 틀이 아니고 델리만쥬모양의 틀에 팥과 슈크림을 넣는다고 우리는 그걸 붕어빵이라고 할 수 있을까요??

 비슷한 생각으로 붕어처럼 생긴 빵을 먹고 싶은데, 내 입맛대로 재료를 채워넣게 해주는 것이 Template함수의 기능이라고 할 수 있습니다.

 

 사용 문법은 굉장히 쉽습니다. vector함수를 사용하는 것과 굉장히 비슷한데요,  vector함수의 형식을 들여다보면서 설명해보겠습니다.

#include <vector>
using namespace std;

int main(){
	vector<int> v;
	return 0;
}

 위의 #include나 using namespace는 다들 아실 것이고 vector<int> v;라는 선언을 할 때 vector라는 틀속에 어떤 원소들을 넣을 것인지 vector라는 녀석에게 알려주어야 컴퓨터가 잘 인식할 수 있습니다.

위의 코드를 번역하면

 vector의 속을 int로 채운 붕어빵을 나는 v라고 하겠다! 정도가 위의

vector<int> v;

가 될 수 있습니다.

 template 사용법을 써보면

#include <iostream>
using namespace std;

template <typename T> // 현재 클래스가 template이라는 것을 명시, typename T대신에 class [원하는 이름] 가능
class TemplateTest {
private :
	T info; 
public :
	void setInfo(T _info);
	T getInfo();
};

int main() {
	TemplateTest<int> intTest;
	intTest.setInfo(2);

	TemplateTest<string> strTest;
	strTest.setInfo("string");

	cout << intTest.getInfo() << endl;
	cout << strTest.getInfo() << endl;

	return 0;
}

template<typename T> // TemplateTest클래스의 함수가 template이라는 것을 명시 
void TemplateTest<T>::setInfo(T _info)
{
	info = _info;
}

template<typename T>
T TemplateTest<T>::getInfo()
{
	return info;
}

가 됩니다.

 

현재 실습은 이렇게 main.cpp같은 하나의 파일에 다 적기때문에 헷갈일 일이 없지만, 나중에 점점 프로그램이 커지다보면 .h와 .cpp에 적는게 보기 더 편해지다보니 잊게 되더라구요,,,, (멍충) .h와 .cpp가 있다면 .h에 모든 것을 적어두는 것이 좀 더 예쁘겠죠..?

 

다시 본론으로 돌아와서 설명을 하자면 class를 생성할 때 class 함수 명 위에 template <typename T>를 명시함으로써 이 class는 template 클래스라는 것을 알려주어야합니다. 그래야만 생성할 때 <>이 꺾새에 넣어줄 데이터 형식을 담아달라는 말을 하게 됩니다.

typename T 대신에 class T도 가능하고 typename C처럼 뒤에 오는 것은 변수를 선언한것처럼 사용하는 것이니 작성하기 편하신 것으로 작성하여 사용하시면 되겠습니다. 그리고 내부 함수들에게도 저렇게 template<typename T>아래에 반환 타입 class명<typename>::함수명(파라미터)가 들어가야만 정상적으로 인지하니 기억하셔야합니다!! 

물론 기억하지 않고 visual studio를 사용하고 계시다면 [ctrl + .]을 누르면 갓쥬얼 스튜디오가 알아서 함수를 정확한 위치에 정확하게 구현 부분을 만들어줍니다. 그러면 class를 정의한 .h나 .cpp에 그대로 적어줄텐데 절!대!로! 다른 곳으로 보내버리시면 안되고 함께 있도록 해주셔야 합니다!!

 

 누가 봐주실지는 모르겠지만,,, 보시는 분은 행복한 코딩을 하시기 바랍니다.!!


※주의사항

꺾새 안에 들어가는 data type이 직접 작성한 class라면 그 class에게 >, < , ==, = , <<(cout operator)과 같은 operator들을 오버로딩해주는 것이 좋습니다.

 

template을 일반적이게 사용하려 하는데 특정 class의 특수한 함수를 사용하는 template이라면 더 이상 template이 아닌 팥 붕어빵을 위한 팥 붕어빵 틀이 되는 것입니다!

 

사용할 때 이것 주의해주세요!!


 TMI 잡소리..


사실 저는 되게 게으르고 건방져서 왜 저렇게 귀찮게 자료구조 class를 쓰고 <data>형식을 써야하는지 툴툴대곤 했었습니다. 그런데 얕은 지식으로 공부를 해보니 당연한 것을 가지고 징징대는 절 쉽게 발견할 수 있었습니다.

C++에서 배열을 작성할 때 우리는

int arr[10];

과 같은 형태로 배열을 선언하곤 했었습니다.

 이것을 분석해보면 arr이라는 배열을 만들 것인데 배열의 데이터는 int이다 그리고 나는 int 10칸을 가져가겠다! 라는 선언입니다.

 

 컴퓨터는 가지고 있는 메모리 내에서 우리가 요청한 데이터들을 담을 그릇을 만들어 주어야 합니다. 그러려면 미리 메모리를 잡아둬야하는데 컴퓨터는 뭘 얼마나 잡아둬야 안전하게 이 데이터들을 담을 수 있는지 알아야 우리가 원하는 것을 실행해 줄 수 있을 것입니다.

 

 그래서 arr[10]d은 int라는 변수 타입(4byte)를 10칸 정도 잡겠다. 라는 말이 되고 그것은 arr은 40byte정도를 확보해주면 되겠군!이 됩니다.  이렇게 친절하게 우리가 선언을 해주면 컴퓨터는 arr이라는 배열의 첫 주소로부터 40byte정도 까지는 arr이 갖고 있는 데이터 영역이군!!! 하고 이해를 하게 되는 것이죠.

 

 사용할 시 arr[1] 이라는건 arr 배열은 int니까 4byte씩 읽을 껀데, 내가 원하는 데이터는 arr 주소 + 4byte만큼의 주소를 더한 곳부터 4byte의 데이터를 읽겠다! 라는 의미로 해석이 될 수 있습니다.

 

 이렇게 배열에게 어떤 데이터 저장할 때 확보해야할 메모리를 알려주는 것 처럼 template class를 쓰면 어떤 크기의 자료를 담아줘야하는지 모르기 때문에 <>꺾새 속에 data type을 선언해주어야합니다. 그래야 template class를 선언했을 때 이 class가 필요로하는 메모리는 어느정도군!! 하고 컴퓨터를 이해시키는 것입니다. 

 

 붕어빵에 또다시 비유를 하자면 팥을 넣은 붕어빵과 슈크림을 넣은 붕어빵을 틀에 넣었을 때 우리는 밖에서 그냥 보면 무엇이 들었는지 모릅니다. 슈크림 붕어빵이면 2분을 구워야하는데 팥이 들어간 붕어빵은 1분을 구워야하는 경우 우리는 팥 붕어빵을 1분만에 꺼내주는 타이머가 필요하게 됩니다. 그러기 위해서는 팥 붕어빵이라는 표시를 붕어빵 틀 위에 명시해주면 우리는 붕어빵을 1 분뒤에 꺼내야한다는 것을 쉽게 알 수 있습니다.

 

 이런 느낌으로 template 사용 시 <dataType>을 명시해주는 것입니다

 얕은 제 지식으로 중구난방 헛소리를 한 것 같은데 부디 지나가는 누군가에게 도움이 되길 바라며 한 줄 적어봅니다.

 이걸 읽어주셔서 정말 감사합니다.!

Comments