jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다. 3ds Max를 사용해서 게임용 3D 캐릭터를 셋업하는 방법
이를 위해 오랜 실무를 경험해 온 저자의 고급 노하우들이 공개
위 내용은 GameDevForever의 저자분들의 홍보를 위하여 운영진 자체적으로 올린 광고이며 일체의 수익이 없습니다.(밥좀사줘요~)
Posted by 터너 (TerNer)

[이전 글]

The Modernest C++ #0 - 시작하며

The Modernest C++ #1 - 템플릿 메타프로그래밍 (Template Metaprogramming)


요번 2주 동안 정말로 말도 못할 정도로 바빠서 컴퓨터 앞에도 못앉고 개발도 못하고 살았네요.. ;ㅅ; 그래서 이번주 부터는 버닝하고(?) 글을 써보도록 하겠습니다 ㅠㅠ 용서해주세요 독자 여러분들 m(_ _)m



타입을 가지고 놀아보기, type_traits


자, 저번 연재 글 까지는 템플릿 메타프로그래밍의 정의를 알아보았다면 이번 글 부터는 실전에서의 템플릿 메타프로그래밍을 접해볼 시간입니다. 템플릿 메타프로그래밍 자체가 가독성에서 불리한 면을 가지고 있지만 그래도 잘 따라오셨으면 좋겠습니다 :^)


우선 시작하기에 앞서, boost 라는 라이브러리 이야기를 해보도록 하겠습니다.



<boost 라이브러리의 로고 이미지>


https://ko.wikipedia.org/wiki/Boost - 위키피디아 <Boost> 항목


boost는 여러 개발자들이 모여서 개발한 하나의 큰 라이브러리 프로젝트이며 상기한 위키피디아 링크에서 볼수 있듯이 실제 C++ 표준 위원회에 소속된 개발자 분들이 다수 참여하여 만든 라이브러리라 믿고 사용할수 있습니다. 


boost 라이브러리는 mpl 이라는 이름의 템플릿 메타프로그래밍 라이브러리를 가지고 있습니다. 굉장히 실사용에 있어서 용도가 방대하고 기능도 많아 boost 라이브러리를 채택하는 프로젝트에 있어서 많이 사용되는 라이브러리 이기도 합니다. 이런 부분에 있어서 우리는 모범 답안이자 교과서와도 같은 mpl 라이브러리를 보고 따라 구현해보면서라도 템플릿 메타프로그래밍에 대한 이해도를 높이는게 중요합니다.


C++11 표준에서는 이미 boost 라이브러리의 여러 템플릿 메타 함수[각주:1]를 채택하여 이용중에 있는데 (is_integral, is_floating_point ….), 우리는 이제 이런 내용을 직접 구현해보는 시간을 가질겁니다.




시작하기 전에..


우리는 시작하기 전에 몇가지 기본적인 기능을 가진 메타함수를 작성해야 합니다, 이를 테면 두 타입을 비교하는 is_same 과 같은 것들을 구현해 놓으면 상속등을 이용하여 더 쉽게 프로그래밍 할수 있게 되기 때문에 후술하는 메타 함수들은 적어도 구현 방법 정도는 알아두시는 것이 좋을것이라고 생각합니다.


또, 메타 함수들을 직접 구현해보면서 우리가 C++ 언어를 배웠을때 스쳐지나갔던 상식들을 다시 일깨워 보면서 템플릿 메타프로그래밍에 있어 중요히 요구되는 C++의 문법이나 기능들을 다시금 살펴봄으로서 조금더 생소한 기술에 다가가는 시간을 가져보도록 하겠습니다. 조금은 어려울지 모르더라도 기본적인 C++ 지식만 가지시면 쉽게 따라오실수 있으실겁니다.




<두 타입을 비교하는 is_same>


is_same 은 C++11 표준안에 채택된 메타 함수이자 boost::mpl 라이브러리에도 포함되어있는 가장 기본적인 메타 함수입니다. 이 메타 함수의 기능으로는 템플릿 인수로 받은 두 타입이 동일한지를 체크하는 간단한 메타 함수입니다. 하지만 이런 간단한 기능을 가진 메타함수는 나중에 등장할 많은 메타 함수의 상속 대상이 되는 등의 쓸모가 굉장히 많으므로 절대 놓쳐서는 안될 중요한 메타 함수입니다.


우선 is_same 메타 함수의 구현 내용을 보도록 하겠습니다 :




자, is_same 메타 함수는 위 스크린샷에서 보실수 있듯이 굉장히 구현이 쉽습니다. 4번 라인의 is_same 구조체의 정의를 보시면 일단 메타 함수의 목적 자체가 두 타입이 동일한지 여부를 판단하므로 템플릿 인수를 두가지 받도록 구현이 되어있습니다. 여기서 주목해야 할건 is_same 구조체의 기본 정의의 value 값이 false 라는 점입니다.


왜 false 인지 의아해하실분이 있으시리라 믿는데, 이는 밑 10번 라인에 위치한 템플릿 특수화를 이용한 is_same 구조체의 정의를 보시면 됩니다.


템플릿 특수화 (Template Specialization) 란?


http://www.gamedevforever.com/323 - 친절한티스님 < 템플릿 특수화 (Template Specialization) >

https://en.wikipedia.org/wiki/Generic_programming#Template_specialization - 영문 위키피디아 < 템플릿 특수화 >


템플릿 특수화는 템플릿 매개변수를 특정한 값이나 타입으로 미리 정해주며 정의함으로서 클래스·함수 템플릿 호출시 미리 정해준 값이나 타입에 맞춘 정의에 맞게 동작하도록 하는 방법을 말합니다.


10번째 라인의 is_same 의 특수화된 정의를 보면 기존 정의에 템플릿 매개변수로 정의한 T1, T2 가 템플릿 매개변수 T 와 같을시에 분기하게 되는데 쉽게 생각해보자면 이렇습니다. 20번째 라인에 호출한 is_same 구조체의 템플릿 매개변수 값은 [T1 = int, T2 = float] 가 될것이며 22번째 라인에서 호출한 is_same 구조체의 템플릿 메개변수 값은 [T1 = int, T2 = int] 가 될 것입니다.


컴파일러는 이를 [T = int] 로 인식하게 됩니다, 우리의 똑똑한 컴파일러는 is_same 구조체의 템플릿 매개변수인 T1, T2 가 똑같으므로 하나의 T로 인식하게 되는겁니다. 그게 논리적으로도 맞는 처리 방식이기도 하기 떄문입니다. 그런 처리 방식을 거치게 되어 만일 T1, T2 가 동일한 어떠한 타입인 T를 가지게 되었다면 value 값이 true 가 되게 됩니다. 하나의 트릭과 같은것이죠. 꼼수라고 볼수도 있고 말이지요


그렇다면 실행 결과는 어떻게 되었을까요?



아주 잘 동작합니다, 첫번째 출력은 int 와 float 가 같은 타입인지 비교하는 식이었으므로 false (0) 이 반환되었고, 두번째 출력에 있어 int 와 long 이 같은 타입인지 비교하는 식이었으며 false (0) 이 반환되었습니다. 마지막으로 int 와 int 가 같은 타입인지 비교하는 식이었고 true (1) 가 성공적으로 반환되었습니다. 이런식 입니다. 템플릿 메타 프로그래밍은 쉬우며 우수한 성능을 자랑합니다. 마치 C#의 리플렉션을 C++ 에서 더 싸게 구현하는 느낌입니다.


다음으로 이제 실전에서의 메타 함수들을 보도록 하겠습니다.




<타입을 검사하는 메타함수>


타임을 검사한다는 것은 어떠한 타입이 void 인지 포인터 타입인지, 참조 타입인지, 실수형 데이터 타입인지, 정수형 데이터 타입인지 등을 쉽게 구분할수 있도록 하는 기능을 말합니다. 위 is_same 함수를 이해하신 분들은 어떻게 구현할지 쉽게 파악이 가능하실거라 믿습니다. C++11 표준이나 boost::mpl 라이브러리에 있는 type_traits 의 메타 함수들을 쉽게 도표로 정리 해보자면 이렇습니다.


(도표에 없는 메타 함수는 우리가 직접 구현할수 없거나 매우 힘든 것이기에 뺐습니다, 이를테면 is_class 와 같은 메타 함수는 Visual Studio에 __is_class 와 같은 형태로 컴파일러 확장이 정의되어 있기 때문에 구현이 가능하였고 이를 문법상으로 처리하는건 불가능하기 떄문에 추가를 하지 않았습니다. 혹시라도 방법을 알것 같은 분이 있으시다면 여기 댓글로 다셔도 좋고 C++ 표준 의원회에 보내보시는것도 좋을것 같습니다)




이름


기능

is_void<T>


T 가 void 타입인지 검사


is_null_pointer<T>


T 가 nullptr_t 타입인지 검사


is_integral<T>


T 가 정수형 데이터 타입인지 검사


is_floating_point<T>


T 가 실수형 데이터 타입인지 검사


is_array<T>


T 가 정적 배열인지 검사


is_pointer<T>


T 가 포인터 타입인지 검사


is_fundamental<T>


T 가 정수형 혹은 실수형, nullptr_t 타입인지 검사

 

is_arithmetic<T>


T 가 정수형 혹은 실수형 타입인지 검사


is_compound<T>

 

T 가 정수형 혹은 실수형, nullptr_t 타입을 제외한 모든 타입인지 검사


is_reference<T>


T 가 참조형 타입인지 검사


is_member_pointer<T>


T 가 멤버 객체 (변수) 혹은 멤버 함수 포인터 인지 검사


is_const<T>


T 가 상수 타입인지 검사


is_volatile<T>


T 가 volatile 형식 한정자를 가진 타입인지 검사


is_signed<T>


T 가 부호 있는 수를 가지는 타입인지 검사


is_unsigned<T>


T 가 부호 없는 수를 가지는 타입인지 검사




자, 이 메타 함수들이 우리가 직접 구현해볼 메타 함수들입니다. 너무 많고 장대하다고 걱정하지 마셔도 되는것이, 대부분 is_same 과 같은 메타 함수만 작성할줄 알면 충분히 구현할수 있는 내용의 메타 함수들 뿐이기 떄문에 심하게 걱정은 안하셔도 좋습니다 :^)




<is_void, is_null_pointer 메타 함수 구현하기>

먼저 도표로 보여드렸다시피, 이 두 메타 함수는 타입을 체크하는 기능밖에 하지 않습니다. 다른 많은 타입을 체크하는 것도 아닌 그저 단 하나의 타입을 체크하는 것에 불과하기 때문에 구현이 매우 쉽습니다. 사실 저는 저 두 함수의 실 사용 상황을 C++ 프로그래밍을 하면서도 겪어보지 못했기도 했지만 그래도 연습삼아 구현해보는 시간을 가져봅시다.


우선 코드를 직접 봅시다 :





3, 4번째 라인의 true_type 과 false_type 은 그저 매번 값을 나타내기는 귀찮으니 값을 나타내주는 인터페이스와 같은 역활을 합니다. 7, 9번째 라인의 is_same 은 위에서 서술한 그대로입니다. 이제 12, 14번째 라인을 눈여겨서 보시면 되는데 그저 is_void 함수는 템플릿 매개변수인 T 를 받아 void 와 비교하거나 C++ 표준 라이브러리에서 지원하는 nullptr_t 와 비교하는 작업 뿐입니다. 아주 쉬운 작업이지요.


자 이제 출력 값을 한번 보겠습니다. 예상대로라면 순차적으로 0 1 1, 0 1 1 1 이 나와야 정상일 것입니다 :



엥? 예상했던 결과와는 사뭇 다릅니다. 출력 값을 따라 살펴보니 const 한정자를 붙인 타입은 동일한 결과가 아니라는 값을 내놓고 말아버립니다. 이러면 프로그래머가 const 한정자가 붙은 타입에 대한 메타 함수를 더 작성해야 하는걸까요? 아닙니다. 여기서 우리는 하나의 트릭을 더 이용해야 합니다, 바로 const 한정자를 제거해주는 메타 함수를 작성하는 것입니다. 여기서 부터 약간 머리가 아파지는 구현이 나오게 됩니다, 하지만 걱정하지 마세요. 어려워도 독자 여러분들에게는 크게 어렵지 않은 구현이라는 것을 알고 있기 떄문에 바로바로 코드를 보고 설명을 해보는 시간을 가지도록 하겠습니다.


백문이 불여일견이라고 일단 코드를 보도록 하겠습니다 :





우리는 이제 12, 14, 17, 19번째 라인을 잘 지켜봐야 합니다. remove_const 라는 이름의 메타 함수가 추가되었습니다. 이 함수들은 특이하게도 다른 메타 함수와는 다르게 value 와 같은 값을 내놓지 않고 타입을 내놓습니다. 이것이 템플릿 메타프로그래밍의 강점중 하나라고 볼수 있는데 메타 함수의 결과값은 값에서 부터 타입까지 지원이 가능해서 더 유연하다는 점을 들수 있을것 같습니다.


나중에 메타 함수를 이용한 if 문 분기와 같은 고급 기법을 설명해드릴때 remove_const 메타 함수와 같이 타입을 결과로 내놓는 메타 함수를 아주 많이 보게 되실것입니다 :^)


잡담은 줄이고 이제 remove_const 메타 함수의 구현이 어떻게 되었는지 살펴봅시다. remove_const 메타 함수는 말 그대로 const 한정자를 제거해주는 함수인데 이 또한 템플릿 특수화를 이용하여 구현하였습니다. 14번째 라인을 보시면 아실수 있듯이 그 어떤 타입을 받던 const 한정자를 받으면 분기를 할수 있도록 처리가 되었습니다. 쉽게 말해 const T 에서 T 만 때올수 있도록 특수화를 한것입니다.


이제 이를 이용해서 17, 19번째 라인을 보시면 remove_const 메타 함수를 이용하여 입력된 템플릿 매개변수 값을 넘기고 메타 함수의 결과 타입인 내부 타입 type 을 호출함으로써 그 어떤 타입을 템플릿 매개변수로 보냈던 간에 is_same 메타 함수는 const 한정자가 없는 순수한 타입만을 받게 되고 이로써 const 한정자가 붙은 여부를 가리지 않고 타입 분간이 가능하게 되었습니다.




<is_integral, is_floating_point 메타 함수 구현하기>


이제 부터는 살짝 어려워집니다. 곰곰히 생각해봅시다. is_integral은 분명 정수형 데이터 타입인지를 체크하는 메타 함수인데 이를 어떻게 구현해야 할까요? 정수형 데이터 타입만의 특성이 있을까요? 안타깝게도 없습니다. 우리는 이것을 대응되는 타입을 수동으로 전부 구현해야 합니다. 걱정하지 마세요, 그렇다고 거창한것도 아닌 그저 코드 몇줄이면 되니까요. 이럴떄 매크로를 이용하면 되는겁니다.


is_integral 의 구현부를 보도록 하겠습니다, is_floating_point 메타 함수는 is_integral 메타 함수와 구현 방식이 매우 비슷하기 떄문에 생략하도록 하겠습니다. 사실 스크린샷을 찍을려는데 모니터에 넘쳐서.. :



is_same 메타 함수는 지금은 필요가 없으므로 뺐습니다, 12번째 라인을 보면 is_integral 이 아닌 is_integral_base 라는 메타 함수를 먼저 선언해 준 다음에 14번째 라인을 보시면 특수화를 쉽게 매크로로 할수 있도록 define 한 뒤에 16~27번째 라인까지 모든 정수형 데이터 자료형을 특수화 해줍니다. 안타깝게도 이러지 않으면 구현할수 없기 때문에 이런식으로 구현을 해줄수 밖에는 없습니다.


30번째 라인을 보면 is_integral 메타 함수를 정의 해준 다음 is_integral_base 구조체를 상속한 뒤 템플릿 매개변수로 const 한정자를 제거한 타입을 넘겨주고 있습니다. const 한정자가 붙은 여부에 따라서 정수형, 실수형의 여부가 달라지는건 아니기 때문에 제거를 해주고 넘겨줍니다. is_integral_base 메타 함수가 만들어진 이유도 const 한정자를 제거하기 위함입니다.



잘 출력됩니다. 실수형 데이터는 정수형이 아니므로 정직하게 false (0) 을 내놓는 것을 보실수 있습니다. is_floating_point 메타 함수도 별것 없이 위와 동일한 방법으로 float, double, long double 과 같은 타입을 특수화 하는 것으로 쉽게 구현이 가능합니다.




<is_fundamental, is_arithmetic, is_compound 메타 함수 구현하기>


이번도 뭔가 이름이 길고 거창해 보이실수 있으시겠지만 이 세가지 메타 함수는 동일한 조건이 있습니다. is_arithmetic 메타 함수는 그저 타입이 정수형, 실수형일때 값을 반환 하는것이며, is_fundamental 메타 함수는 is_arithmetic 에 nullptr_t 를 검사하는 로직을 추가해주는 것과 동일하다고 생각하시면 됩니다. 마지막으로 is_compound 메타 함수는 정수형, 실수형, nullptr_t, void 가 아닌 모든 타입일때 true 를 반환하는 간단한 함수입니다.


이를 어떻게 구현해야 할지, 방금 전처럼 매크로를 써야 하나 생각 하시는 분들도 있을지 모르겠으나 그러지 않고 방금 구현한 코드가 있기 때문에 그것을 재활용 하면 됩니다.


자, 뭔가 많이 생겼습니다. 우리가 봐야할건 64번째 라인부터 76번쨰 라인까지 전체를 다 봐야 합니다. 우선 value_type 이라는 메타 함수는 그저 템플릿 매개변수로 비형식 매개변수로 bool 타입의 값을 받아서 true 일시 true_type, false 일시 false_type 과 동일하게 동작하도록 구현한것입니다.


비형식 템플릿 매개변수란?


템플릿 매개변수는 타입 뿐만 아니라 정수형 데이터 값도 받을수 있습니다. 이를테면 int 와 bool 같은 형식도 받을수 있기 때문에 이를 이용해서 수학적 연산도 가능하며 여러가지 처리가 가능합니다. 이용하는 방법은 쉽게 typename 이 아니라 이용할 타입을 적고 그 뒤에 템플릿 매개변수 이름을 적으면 됩니다.


예) <정수형 데이터 타입> <템플릿 매개변수 이름>


이제 이것을 이용해서 68번째 라인의 is_arithmetic 을 구현하였는데 뭔가 좀 허전합니다. 원래 구현할려던 생각과 같으면 매크로를 무진장 쓰고 있었을 텐데 간단히 한줄이면 쉽게 구현이 가능하게 되었습니다. 먼저 구현한 is_integral 과 is_floating_point 를 이용하여 구현하였고 어차피 두 메타 함수는 타입이 아닌 결과 값을 반환하므로 value_type 메타 함수를 상속하여 false_type, true_type 을 구분할 수 있도록 하였습니다.


그렇게 is_arithmetic 메타 함수의 조건과 맞게 is_integral, is_floating_point 메타 함수를 이용하여 정수형이나 실수형 데이터 타입인지 구분할 수 있도록 하였습니다. is_fundamental 메타 함수는 is_arithmetic 메타 함수와 동일하지만 nullptr_t 혹은 void 인지 확인하는 로직이 추가되므로 is_null_pointer 와 is_void 메타 함수를 추가하여 구현할수 있습니다. 


is_compound 메타 함수는 정수형, 실수형, nullptr_t, void 를 제외한 모든 타입인지를 검사하는 메타 함수 이므로 그저 is_fundamental 메타 함수의 결과 값에 NOT 연산자를 부여해서 값을 뒤집어 value_type 메타 함수에 넘겨 줬습니다.


생각해보면 value_type 은 비형식 템플릿 매개변수를 받는 메타 함수 이며 지금까지 구현한 모든 값을 반환하는 메타 함수는 오직 true, false 만을 반환 하였으므로 그를 이용하여 OR 연산자를 이용해 조건을 만들어줌으로서 코드를 재사용 할 수 있었던 것입니다. 결국에 value_type 메타 함수로 전달되는 값은 하나일테고 OR 연산자의 결과이기 때문입니다.






예상했던 대로 아주 잘 처리가 됨을 알수 있습니다. 이런 처리를 하고도 타입을 체크하는데 드는 부하는 0 이며 사실상 컴파일 타임에 모든 연산이 이루어 지기 때문에 실행시간에 발생하는 부하는 없다고 봐도 무방합니다.




<is_pointer, is_reference, is_const, is_volatile, is_signed, is_unsigned 메타 함수 구현하기>


뭔가 많아진것 같지만 기분탓 일겁니다. (..) 하지만 상기된 6가지 메타 함수는 모두 구현 방법이 비슷해서 그렇게 크게 어렵지는 않을 것입니다. 그저 특수화를 이용해서 어떤 한정자나 키워드가 붙어있는지 알수 있으므로 구현 방법은 오히려 매우 쉽다고 볼수 있을 정도의 메타 함수이니 잘 따라와 주셨으면 좋겠습니다 :^)





뭐..뭔가 길어보이지만 기분 탓 일겁니다. is_pointer 메타 함수는 인터페이스가 있는데 이는 is_integral 때와 동일하게 const 한정자를 제거하기 위함이며 템플릿 특수화를 이용해 모든 타입에 대하여 포인터 연산자(기호)가 붙어있는 타입의 경우 포인터로 판별하도록 구현하여 포인터 타입인지 체크하기가 용이해졌습니다.


is_reference 메타 함수는 약간 특이한데, 독자 분들중 몇몇 분들은 '어? 왜 & 가 두개 붙는 것도 있지?' 하시는 분들도 있으리라 생각합니다. 그 이유로는 rvalue reference, lvalue reference 에 대한 대응이며 rvalue reference 타입일 경우 T&&, lvalue reference 타입일 경우 T& 로 템플릿 매개변수에 추가가 되므로 그렇게 처리하였습니다.


is_const 와 is_volatile 메타 함수는 그저 특수화를 이용하여 is_pointer 와 동일하게 const 제한자가 붙어있는 모든 타입에 대하여 true 를 반환하도록 작성하였습니다.


이제 대망의 is_signed, is_unsigned 차례인데 106, 113번째 라인을 보면 아실 수 있듯이, value_type 을 이용해 구현을 합니다만 템플릿 매개변수 T 로 받은 자료형을 -1 과 0 으로 초기화 하여 임시 변수를 만들어 비교함으로서 signed, unsigned 인지 판별하도록 구현할 수 있습니다. 만일 타입이 signed 라면 -1 보다 0 이 당연히 클것이고 unsigned 라면 -1 은 0 보다 크기 때문에 이를 이용한 하나의 트릭과 같은 방법입니다.


그리고 unsigned, signed 를 판별하는 메타 함수에 클래스나 기타 잘못된 정보가 들어오면 안되므로 _is_arithmetic 비형식 템플릿 매개변수를 이용해 T 로 넘겨받은 타입이 정수형이나 실수형이 아니라면 false 를 반환하도록 구현할 수 있습니다.




잘 출력 됩니다. is_signed, is_unsigned 구현부에서 정수형, 실수형 데이터 타입 이외의 타입은 false_type 을 상속 받게 했는데 잘 작동되나 싶어 signed, unsigned 를 상속한 열거형의 타입을 넣어 봐도 false_type 으로 나오니 아주 성공적입니다.




<is_member_pointer<T> 메타 함수 구현하기>


이 메타 함수는 어떠한 클래스나 구조체 내부에 있는 멤버 함수나 멤버 변수임을 판단하는 메타 함수 입니다. 우리가 구조체나 클래스의 멤버 포인터의 타입을 이용해 매개변수를 만들때와 같은 상황을 생각해보면 하나의 규칙이 있음을 알게 됩니다. 바로 타입으로 사용할 멤버를 소유하는 클래스나 구조체의 명을 앞에 써준 후에 :: 연산자를 이용하게 되는데 이를테면 int foo::* 이렇게 정의를 한다면 foo 클래스 혹은 구조체에 있는 int 형 변수의 포인터가 됩니다. 


이를 이용해서 구현해준다고 생각하면 매우 쉽게 구현할 수 있습니다 :




구현 방식은 대략 위에서 설명한 내용과 동일합니다. 122번째 라인을 보시면 일단 모든 타입을 받게 메타 함수를 정의 한 후, 124번째 라인의 정의에 따르면 만일 템플릿 매개변수로 받은 타입이 멤버 포인터와 같은 형식이라면 122번째 라인이 아니라 124번째 라인에서 정의한 메타 함수가 호출되게 되며 true_type 을 상속하는 is_member_pointer_base 메타 함수가 호출되게 되는겁니다.


잘 작동 하는지 결과를 보자면.. :






아주 잘 작동하는 것을 보실수 있습니다. 




<is_array<T> 메타 함수 구현하기>


이 메타 함수는 위 도표에 나와있는 그대로 정적 배열인지 판단하는 메타 함수 입니다. 동적 배열은 포인터이기 때문에 확인이 불가능하지만 동적 배열은 확인이 가능하고 심지어는 정적 배열의 인덱스 까지 확인할수 있는 메타 함수를 구현할 수도 있습니다. 이는 후설토록 하겠습니다. 




코드를 보시면 아실수 있으시겠지만 135번째 라인을 보시면 템플릿 특수화를 이용하여 따로 배열의 크기를 받는 arrSize 라는 이름의 비형식 템플릿 매개변수를 이용하여 주솟값 연산과 같은 번거로운 작업을 거치지 않고서도 정적 배열의 크기를 얻어올 수 있습니다. 133번째 라인은 크기가 지정되지 않은 정적 배열을 타입으로 받아올수 있도록 구현한 것이며 문법상 틀린 부분이 없기 때문에 잘 동작합니다.



잘 작동하는 것을 확인할 수 있으며 객체던 기본 자료형 타입이던 여부를 떠나서 모든 정적 배열에 동작이 됨을 확인 할 수 있고 크기가 지정되지 않은 정적 배열 형식도 처리할 수 있음을 확인할수 있습니다.




마치며..

연재를 시작하게 됬을때부터 누차 말씀드린 내용이지만서도 템플릿 메타프로그래밍은 굉장히 프로그래머로써, 효율로써 상당히 이득인 기술이기 때문에 익혀두시면 분명히 도움이 될거라고 저는 믿어 의심치 않습니다. 위에 적어놓은 내용을 보시고 직접 따라 구현해보시면서 템플릿 메타프로그래밍에 대한 이해를 넓히셔서 자신만의 코드를 작성해보는 연습을 꼭 하시기 바랍니다. 제가 위에 적어놓은 메타 함수들 뿐만 아니라 메타 함수의 종류는 그 쓰임새에 따라 굉장히 많기 때문에 이를 잘 습득하고 상황에 맞게 구현하는게 굉장히 중요하다고 생각합니다.


새벽 4시에 쓴글인데 7시가 다되서야 끝났네요. 원래는 메타 함수 1~2개씩 연재글을 나눠쓸까 하다가 그건 너무 괴씸한것 같아서 이렇게 한꺼번에 써봅니다. 다음 글 부터는 if_ 나 템플릿 메타프로그래밍을 이용한 수학 연산 라이브러리를 작성하고 그에 대한 내용을 써보도록 하겠습니다. 긴 글 읽어주셔서 감사합니다.






  1. 메타 함수란 이전 글에서 볼수 있었던 is_int 와 같은 객체를 메타 함수라고 합니다. 컴파일 타임에 호출되어 처리될수 있는 하나의 함수와 같은 기능을 합니다. [본문으로]

댓글을 달아 주세요

  1. Favicon of http://blog.naver.com/tlsehdgus321 뭐지What 2015.10.28 08:45 신고  댓글주소  수정/삭제  댓글쓰기

    잘봤습니다 ㅎㅎ

  2. Favicon of http://blog.naver.com/accadia777 힙돌이동남아 2015.11.05 19:08 신고  댓글주소  수정/삭제  댓글쓰기

    일단 선댓글! 잘보겠습니다.

  3. 카일 2016.02.05 13:02 신고  댓글주소  수정/삭제  댓글쓰기

    본문과는 상관 없는 질문이 하나 있습니다.
    템플릿의 구현을 cpp넣고 컴파일을 하면 정의를 찾을 수 없다고 나오는데(런타임에 인스턴스를 생성하는 시점에서)
    그래서 찾아보니 해결책이
    1) 구현을 헤더에 넣는다.
    2) 헤더에 명시적으로 타입을 지정한다.(ex>template class Point<int>; )

    위에 두가지라고 현재까지는 이해하고 있습니다
    1)은 구현을 헤더에 넣게 되면 수정할대마다 컴파일이 시간이 길어지고
    2)은 명시적으로 타입을 헤더에 지정하면 번거로워지고 템플릿 강점이 떨어지는 것이 아닌가 생각이 드네요

    제가 visual studio 에서 컴파일해서 제약이 있는 것인지
    아니면 다른 방법이 있거나 제가 잘못알고 있는 것인지 모르겠습니다

    • Favicon of http://cloudcie.blog.me 터너 2016.05.02 01:57 신고  댓글주소  수정/삭제

      원래 .cpp 파일에도 템플릿 클래스를 선언하고, 구현할수 있습니다. 다만 헤더 파일에 선언만 해놓고 소스파일에 구현하는 방법은 불가능하죠. 템플릿 매개변수를 지정해줘야 되요. 컴파일 시간이 길어지는 문제는 Precompiled Header 항목을 찾아보시거나 해보세요. 어차피 템플릿 특성상 코드가 변경되면 컴파일을 다시 해야하는건 어쩔수 없는 것이기도 하죠. 클래스 템플릿의 매개변수가 정해진후 코드가 생성되는건 어차피 컴파일 타임이라 그런 부분에서는 템플릿이 약세를 보이죠. <T> <- 저기 T 에 뭐가 들어올지는 세상 그 누구도 모르는 미스테리 일테니까요.

  4. 바람돌이 2016.05.10 18:06 신고  댓글주소  수정/삭제  댓글쓰기

    예전부터 찾아본다는 TMP에 대해서 너무나도 자세히 설명을 해주셔서 너무 재미있게 잘봤습니다.



티스토리 툴바