원문 : http://www.cprogramming.com/tutorial/template_specialization.html

주의 : 번역이 개판이므로 원문을 참조하세요.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.

정보 : 가장 아래에 있는 관련 기사들도 같이 보시면 좋을 것 같습니다.


Template Specialization and Partial Template Specialization


Template Specialization


Template 을 가지고 작업을 하는 많은 경우에, 당신은 모든 가능한 data type 을 위한 범용적인 버전의 template 을 작성할 것이며, 그것을 그대로 둘 것이다 -- 모든 vector 는 아마도 정확히 같은 방식으로 구현될 것이다. Template 특수화라는 아이디어는 기본 template 구현을 덮어 써( overriding ) 특정 type 을 다른 방식으로 다루는 것을 의미한다.


예를 들어 대부분의 vector 들이 주어진 type 에 대해 배열로서 구현될 것이지만, 당신은 약간의 메모리를 절약하기로 결심하고, bool 의 vector 들을 vector 내의 하나의 요소( entry )가 각 bit 와 연관되는 integer 의 vector 로서 구현할 수 있다. 그래서 당신은 다음과 같은 두 개의 개별적인 vector class 들을 가질 수 있다. 첫 번째 class 는 다음과 같다.



그러나 그것이 bool 일 때 당신은 실제로는 이렇게 하고 싶지 않을 것이다. 왜냐하면 대부분의 system 들이 1 bit 가 필요함에도 불구하고 boolean type 을 위해 16 bit 나 32 bit 를 사용하기 때문이다. 그러므로 우리는 integer 배열로 data 를 표현함으로써 boolean vector 의 모양을 약간 다르게 만들어야 한다. 그것의 bit 들은 우리가 수동으로 조작하게 된다. ( bit 를 직접적으로 조작하는 것과 관련해 더 알고 싶다면, bitwise operators and bit manipulation in C and C++ 을 참조하라. )


이렇게 하기 위해 우리가 template 과 유사한 것을 가지고 작업하지만 이번에는 template 의 매개변수( parameter ) 가 비어있을 것이라는 것을 지정할 필요가 있다 : 



그리고 그 class 의 이름 뒤에는 특화된 type 을 넣는다 : class className< type >. 이 경우에는 그 template 이 다음과 같다 :



만약 특화된 버전의 vector class 가 범용 vector class 보다 더 다양한 interface( public method 집합 )를 가지고 있다면, 그것은 완벽하게 합리적일 것이다 -- 비록 둘 다 vector template 이지만, 그것들은 어떠한 interface 나 code 도 공유하지 않는다.


이 경우에 특화를 하는 가장 중요한 이유는 더 공간을 효율적으로 이용하는 구현을 허용하는 것이었음을 짚고 넘어 갈 필요가 있다. 그러나 당신은 이것이 쓸모가 있는지에 대해 생각해볼 수 있다 -- 예를 들어, 당신이 어떤 type 에 의존하는 templated class 에 부가적인 method 를 추가하고 싶지만 다른 type 에 대해서는 그렇게 하고 싶지 않은 경우이다. 예를 들어, 당신이 상속을 더 좋아하기는 하지만, 당신은 각 요소의 non-integer 부분을 반환하는 method 를 가지는 double 의 vector 를 가지고 있을 수 있다. 그러한 부가적인 기능을 가지지 않는 double 의 vector 가 존재하지 않도록 막을 특별한 이유는 없다. 그러나 만약 당신이 그것이 쟁점이라고 느끼고 그것을 막고자 한다면, 당신은 template 특수화를 사용해서 그것을 수행할 수 있다.


어떤 template 을 특수화하기를 원하게 되는 다른 경우는 당신이 template 을 저장하고자 하는 class 의 collection 에 구현되지 않은 어떤 동작( behavior )에 의존하는 template type 을 가지고 있을 경우이다. 예를 들어 당신이 > 연산자가 정의되어 있을 것을 요구하는 templated sortedVector 를 가지고 있고, 누군가에 의해서 작성된 class 집합은 overload 된 연산자를 포함하고 있지는 않지만 비교를 위한 함수를 가지고 있다고 한다면, 당신은 template 을 특수화해서 그 class 들을 개별적으로 다룰 수 있다.


Template Partial Specialization


부분 template 특수화는 위에서 기술한 전체 특수화와 비슷한 동기를 가진다. 그러나 이번에는 하나의 특정 type 을 위해서 class 를 구현하는 것이 아니라, 여전히 다른 매개변수화( parameterization )를 허용하는 template 을 작성하는 데서 끝날 것이다. 즉 당신은 하나의 기능( feature )을 특수화하는 template 을 작성하지만, 여전히 그 class 의 user 는 template 의 일부로서 다른 기능들을 선택할 수 있도록 한다. 예제를 통해 이를 좀 더 확실하게 하자.


Vector 의 개념을 확장하는 아이디어로 돌아가 보자. 그러면 우리는 sortedVector 를 가지고 있다. 이것이 어떻게 보일 것인지 생각해 보자; 우리는 비교를 위한 방법을 필요로 할 것이다. 좋다; 만약 연산자가 정의되어 있다면 그냥 > 를 사용하고, 그렇지 않다면 특수화를 한다. 그런데 이제 우리가 정렬된 vector 안에 object 에 대한 pointer 를 가지고 있기를 원한다고 가정해 보자. 우리는 pointer 의 값으로 그것들을 정렬할 수 있을 것이다. 단지 표준 > 비교를 수행하기만 하면 된다( 우리는 오름차순으로 정렬되는 vector 를 가지게 될 것이다 ).



이제 위의 반복문에서 우리는 T type 의 요소들 사이에서 직접 비교를 수행하고 있다는 것을 알게 될 것이다. 대부분의 경우에는  괜찮다. 그러나 아마 pointer 주소가 아니라 실제 object type 상에서 정렬되는 것이 더 말이 될 것이다. 그렇게 하기 위해서 당신은 code 를 다음과 같은 line 을 가지도록 작성해야할 필요가 있다 :



물론 그것은 non-pointer type 에 대해서는 작동하지 않는다. 여기에서 우리가 하고 싶은 것은 그 type 이 pointer 인지 non-pointer 인지 여부에 의존하는 부분 특수화이다( 당신은 pointer 의 multiple level 을 가지고 싶을 수도 있다. 하지만 그냥 단순하게 하자 ).


모든 pointer type 을 다루는 부분적으로 특수화된 template 을 선언하기 위해서, 우리는 이 class 선언에 다음을 추가할 것이다 :



여기에서 주목해야 할 두 개의 syntax point 가 있다. 첫 번째는 우리 template 매개변수 리스트가 여전히 매개변수의 이름을 T 라고 짓고 있지만, 그 선언은 class 의 이름 뒤에 T* 로 붙는다; 이는 컴파일러에게 모든 type 의 pointer 에 대해 더 범용적인 template 대신 이 template 을 연결해 달라고 요청하는 것이다. 두 번째는 T 가 이제 pointer 로 접근하는 type 이라는 것이다; 그것 자체는 pointer 가 아니다. 예를 들어 당신이 sortedVector< int* > 를 선언할 때, T 는 int type 을 참조할 것이다! 이는 당신이 그것을 별표( * )가 붙은 type 이 있을 때 그것을 매칭해 주는 형식이라고 생각하면 이해가 쉽다. 이는 당신이 구현을 할 때 좀 더 주의를 해야 한다는 것을 의미한다 : vec_data 는 T** 이다. 왜냐하면 우리는 pointer 로 구성된 동적 크기의 배열을 필요로 하기 때문이다.


당신은 sortedVector type 이 실제로 이렇게 동작기를 원하는지 궁금해 할 수 있다 -- 결국 만약 그것들을 pointer 의 배열로 삽입한다면, 당신은 그것들이 pointer type 에 의해 정렬될 것을 기대할 것이다. 그러나 이렇게 하는 것에는 실질적인 이유가 존재한다 : 당신이 object 에 대한 배열을 위해 memory 를 할당할 때, 반드시 각 object 를 생성하기 위해 기본 생성자가 반드시 호출되어야만 한다. 만약 기본 생성자가 존재하지 않는다면( 예를 들어 모든 object 가 생성되기 위해서는 어떤 data 를 필요로 한다면 ), you're stuck needing a list of pointers to objects, 그러나 당신은 아마도 그것들이 실제 object 들 자신이 정렬되는 것처럼 정렬되기를 원할 것이다.


그건 그렇고 당신은 template 매개변수에 부분 특수화를 수행할 수도 있다 -- 예를 들어 만약 당신이 fixedVector type 을 가지고 있는데 그것이 ( 동적 memory 할당 비용을 피하기 위해서 )  class 의 사용자가 저장될 type 과 vector 의 길이를 모두 지정할 수 있도록 허용한다고 하면, 다음과 같은 코드를 볼 수 있게 될 것이다 :



그리고 나서 당신은 다음과 같은 구문으로 boolean 들을 부분적으로 특수화할 수 있을 것이다 :



T 가 더 이상 template 매개변수가 아니기 때문에 그것은 template 매개변수 리스트 밖에 있으며, length 만 남게 된다는 데 주의하라. 그리고 그 length 는 ( 범용 template 선언을 할 때는 이름 뒤에 아무것도 지정하지 않는 것과는 다르게 ) 이제 fixedVector 의 이름으로 나타난다. ( 그건 그렇고 template 매개변수가 non-type 이라는 것을 보고 놀라지는 마라 : 그것은 완벽하게 유효하며, unsigned 와 같은 integer type 인 template 인자들을 가지기 위해 유용하게 쓰이기도 한다. )


최종 구현 세부사항이 부분 특수화까지 왔다 : 컴파일러는 완벽하게 범용적인 type 들에 대한 조합, 어떤 부분 특수화, 그리고 완전한 특수화가 존재할 때 어떤 특수화를 선택할까? 일반적인 경험 법칙( rules of thumb )은 컴파일러가 가장 명확한( specific ) template 특슈화를 선택할 것이라고 이야기한다 -- 가장 명확한 template 특수화는 다른 template 선언들에 의해서 받아들여질 수 있는 template 인자들을 가지고 있지만, 같은 이름을 가진 다른 template 들이 받아들일 수 있는 인자를 모두 받아들일 수는 없는 template 을 의미한다.


예를 들어 만약 sortedVector< int* > 가 memory 위치에 의해 정렬되기를 원한다고 할 때, 당신은 sortedVector 에 대한 전체 특수화를 생성할 것이다. 그리고 sortedVector< int* > 를 선언하면 컴파일러는 pointer 에 대해 덜 명확한 부분 최적화를 선택할 것이다. int* 는 전체 특수화와만 일치하지만 double* 과 같은 다른 pointer type 와는 일치하지 않기 때문에 그것이 가장 근접하게 특수화된 것이다. 반면에 int* 는 명백히 다른 template 들이 받아들이는 매개변수가 될 수 있다.




Related articles.

C++ Templates Quiz : 당신의 template 지식을 테스트해 보세요.

Templated classes in C++ : templated class 에 대한 배경 정보.

Templated functions : 함수 template 에 대해 더 많이 배워 보세요.


'Programming > C++' 카테고리의 다른 글

[ 번역 ] Universal CRT 소개  (0) 2015.12.28
[ 번역 ] C++ Modifier Types  (0) 2013.01.02
[ 번역 ] Function Call Operator ()  (0) 2012.12.24
[ 번역 ] explicit( C++ )  (0) 2012.12.24
[ 번역 ] C++ Metadata - Part 1, Singletons and Lookup  (0) 2012.10.31

+ Recent posts