본문 바로가기
프로그래밍/C++

C++] template을 헤더파일에 정의하기. (선언만 하면 왜 안될까?)

by Hwan2 2020. 9. 4.
728x90
반응형

C++ 에는 다른 언어에 있는 template이라는 키워드가 존재합니다.

 

template은 프로그램의 유연성을 제공해주죠.

 

코드 또한 간결해지고요.

 

C++의 코드를 짜다보면 헤더파일에 클래스, 함수 등을 선언만하고 실제 구현은 다른 cpp파일에 정의하게 됩니다.

 

즉, 파일을 분리하는 것이죠.

 

이것의 장점은 코드 관리가 쉬워진다는 점입니다.

 

단점이 된다면 코드를 보는것이 다소 복잡해 질 수도 있지요. 

 

그럼에도 불구하고 분할 컴파일을 많이하고 있습니다. 

 

기능적인 부분들을 분리해서 정의하는 것이 관리에 있어서, 수정함에 있어서 좋은것은 사실이니 말이죠.

 

하지만 템플릿은 헤더파일에 선언만 해서는 동작하지 않습니다.

 

컴파일 시 애러 메시지를 띄워주죠.

 

예시를 보겠습니다.

 

1. template을 헤더파일에 선언.

temp.h

#ifndef __TEMP__H_
#define __TEMP__H_

template<class T>
T add(T aT b);

#endif

add.cpp

#include "temp.h"

template<class T>
T add(T aT b){
    return a + b;
}

main.cpp

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

int main(){

    int num = add<int>(1020);
    std::cout << num << std::endl;
    return 0;
}

g++ compile

 

컴파일 에러가 나온것을 확인할 수 있습니다.

 

Error 메시지를 읽어보자면 "main.cpp에는 int add<int>(int, int) 함수가 정의되어 있지 않다." 라고 합니다.

 

분명히 temp.h 라는 헤더파일을 선언하고 add.cpp라는 파일에 정의를 했는데 말이죠.

 

왜 이런 컴파일 Error가 뜨는지 살펴보고자 합니다.

 

2. 헤더파일에 template을 선언만 하면 안되는 이유.

main.cpp 에서 template을 정의하고 사용한다고 가정해 봅시다.
 

main.cpp

#include <iostream>

template<class T>
T add (T aT b){
    return a + b;
}

int main(){

    int INTnum = add(1020);
    double DOUBLEnum = add(10.320.1);

    std::cout << INTnum << std::endl;
    std::cout << DOUBLEnum << std::endl;
    return 0;
}

output

 

여기선 Angle Bracket선언 없이(add<int>, add<double>) 사용해도 컴파일 과정에서 컴파일러가 자동으로 자료형을 맞추게 됩니다.

 

허면 컴파일 과정에서 add() 라는 template함수가 어떻게 바뀌는지 보겠습니다.

 

해당 main.cpp 코드를 디어셈블한 코드로 본다면 다음과 같이 정의됩니다.

disassemble

 

 

int 형을 받는 add 함수 1개, double 형을 받는 add 함수 1개

 

총 2개의 함수가 정의되어 집니다.

 

그럼 선언만하고 사용하지 않는다면 어떻게 될까요??

 

main.cpp

#include <iostream>

template<class T>
T add (T aT b){
    return a + b;
}

int main() {

    int INTnum = 10;
    double DOUBLEnum = 20.3;

    std::cout << INTnum << std::endl;
    std::cout << DOUBLEnum << std::endl;
    return 0;
}

disassemble

 

add 라는 함수가 정의조자 되지 않았습니다. 

 

즉, 선언만 된 상태로 사용을 안했다는 뜻이죠.

 

감이 오시나요? 왜 헤더파일에 template을 선언만 하면 안되는지??

 

헤더파일에 template을 선언만 한다면, 컴파일 과정에서 template이 어떤 자료형인지 컴파일러가 알 수 없습니다.

 

헤더파일 한에선 사용도 안했을 뿐더러 정의또한 되지 않았으니까요. 때문에 자료형을 몰라 컴파일이 안되는 것입니다.

(add.cpp에 정의되어 있다곤 하지만 object파일을 만드는 과정에서 컴파일러는 add라는 함수를 제외시킵니다.

위에서 설명했다 싶이 add.cpp 함수 한에서 사용되지 않았으니깐요. 

때문에 링크 과정에서 main.cpp가 add()함수를 찾지 못하는 것입니다.)

 

단, 함수를 정의했던 add.cpp에서 해당 template함수를 명시적으로 선언해준다면 오류를 막을 수 있습니다.

 

3. 오류를 막는 개선된 코드

temp.h

#ifndef __TEMP__H_
#define __TEMP__H_

template<class T>
T add(T aT b);

#endif

add.cpp

#include "temp.h"

template int add<int>(intint); //명시적 선언

template<class T>
T add(T aT b){
    return a + b;
}

main.cpp

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

int main(){

    int num = add<int>(1020);
    std::cout << num << std::endl;
    return 0;
}

output

 

명시적으로 선언한다면 add.cpp라는 파일에는 int add(int a, int b) 라는 함수가 정의되어 object 코드에 올라가게 됩니다.

 

때문에 main.cpp에서 링크과정을 통해 함수를 불러올 수 있는 것이죠.

하지만 저렇게 명시적으로 선언한다면 여간 귀찮은 일이 아닐 수 없습니다.

 

또한 template의 간편한 장점도 상실되죠.

 

때문에 template을 헤더파일에 선언하고 싶다면 정의도 같이 해주셔야 합니다.

 

 

4. 헤더파일 내부에 정의된 코드

temp.h

#ifndef __TEMP__H_
#define __TEMP__H_

template<class T>
T add(T aT b){
    return a + b;
}

#endif

main.cpp

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

int main(){

    int num = add(1020);
    std::cout << num << std::endl;
    return 0;
}

output

 


이렇게 된다면 컴파일러가 실행이 되면서 링크를 통해 헤더파일에 정의된 함수를 통해 main.cpp에서 add()함수를 사용할 수 있게 됩니다.

 

 

끝.....

반응형

댓글


스킨편집 -> html 편집에서