2009.06.29 13:58 책 정리/C++ Template

템플릿 코드를 작성 하는 것은 , 일반 코드와 다르다. 이 다름에는 여러가지가 있지만, 컴파일러가 코드를 컴파일 하는 시점이 일반 코드와 다른 것이 이뜸이지 않을까 한다.

컴파일러는 어떻게 인식 하는가?
일반 코드의 경우
1. .h, hpp, hxx, 라는 파일에 선언을 넣어 둔다. 이런 파일을 우리는 헤더 파일이라 부른다.
2. cpp, c, cxx 파일에 정의를 넣어 둔다. 이런 파일을 우리는 C 파일이라 부른다.

이러한 헤더파일과 C파일을 컴파일러가 컴파일하게 되는데, 이러한 결과물을 OBJ 파일이라 한다. OBJ 파일은 단순한 기계어 파일인데, 이러한 OBJ 파일들을 링커가 서로 연결해 주고, 스타트업 코드를 넣어 주면서 실행 파일이 만들어 진다.

템플릿 코드는 바로 이 부분이 다르다.
OBJ 파일을 만들 때, 템플릿 코드를 분리하게 되면, 컴파일러의 번역 단위가 분리되게 되는데, 템플릿 특성상 "사용하지 않는 코드는 인스턴스화 되지 않는다" 그래서 컴파일할 때 현재의 번역 단위에선 선언만 인스턴스화 되고, 본체는 인스턴스화되지 않아 , 링커가 동작할 될 때, 링킹 에러가 나오게 된다.

다음과 같이 파일을 구성하여 컴파일하고 링킹 하면 보다 자세히 알 수 있을 것이다.





이제 컴파일을 시도 하면 다음과 같은 링커 에러를 볼 수 있을 것이다.
"main.obj : error LNK2019: "void __cdecl print_typeof<int>(int const &)" (??$print_typeof@H@@YAXABH@Z) 외부 기호(참조 위치: _main 함수)에서 확인하지 못했습니다."

링커의 에러에서 볼수 있듯이, 해당 정의를 찾지 못한다. 찾지 못하는 이유는 해당 정의를 담고 있는 오브젝트 파일을 만들지 못해서 생길 일이다. 만들지 못하는 이유는 템플릿 코드는 사용하지 않으면 코드 인스턴스화가 일어나지 않아, 컴파일러가 코드를 생성하지 못했기 때문인데, 템플릿의 경우, "같은 컴파일 번역 단위에 놓일 경우, 알아서 인스턴스화 되고, 명시적으로 사용 했을 때, 명시적으로 지정한 것들만 인스턴스화 되고,  키워드를 통해 컴파일러에게 알렸을 때, 일반 분리 모델 처럼(?) 사용 할 수 있다."

여기서 처럼에 ? 가 되어 있는데, 현재까지 일반적인 분리모델과 다르기 때문이다. 이건 나중에 정리한다.

첫째, 포함 모델
가장 일반적으로 사용하는 모델이다. 한 번역 단위로 컴파일러에게 보여주어, 선언과 정의 둘 다 인스턴스화 되게 한다.

둘째, 명시적 인스턴스화 모델
책의 내용을 인용하자면 "저자들은 코드가 성숙했을 무렵에는 후회하게 됐다" 라고 마지막에 정리해 준다. ... 그래도 굳이 알고 싶다면 다음의 파일을 만들고 다시 컴파일 해보길 바란다.

까다로운 몇가지 규칙이더 있는데, 안쓸꺼니까 정리는 패스 한다.

셋째, 분리 모델
키워드인 export 를 사용하면 된다. 템플릿의 정의와 모든 정의되지 않은 선언들에 export 를 표시하면 된다. 하지만 이런게 있음에도 포함모델을 사용 하는 이유1. 모든 컴파일러가 export 키워드를 지원해 주지 않는다. 2. 정의를 포함한 코드를 수정했을 때, 그 정의를 포함한 모든 파일을 다시 재 컴파일 해야 한다. 왜냐하면 눈에 보이는건 분리일 뿐이지, 실상 연결되어 있다. 그러므로 make의 종속성 관리는 무너지게 된다. .. 으헝.. 3. 디버깅이 더 어려워 진다. .... 가나다라맙소사!

마지막으로, 분리 모델은 현재 사용 하기 꺼려짐에도, 컴파일러 개발자가 자신의 삶을 깍아 먹으면서까지 진짜 분리모델을 만들어 줄 수 있을 지도 모르기 때문에, "누가 내 치즈를 옮겼을 까?"를 생각해볼 필요가 있다.

저작자 표시
신고
posted by 농사를 짓는 게임 프로그래머 최익필

댓글을 달아 주세요

  1. df 2010.10.06 15:23 신고  Addr  Edit/Del  Reply

    잘 보고 갑니다~