ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C++ 템플릿의 종류
    @ 16. 1 ~ 17. 1/면접관련 2017. 1. 4. 19:06

    1. 함수 템플릿

    2. 클래스 템플릿


    두 종류의 템플릿은 정확히 동일한 방식으로 동작하지 않는데, 가장 명백한 차이는 오버로드 유무이다.

    보통의 C++클래스와 마찬가지로 클래스 템플릿 역시 오버로드를 할 수 없다.

    역시 C++함수와 마찬가지로 함수 템플릿 역시 오버로드가 가능하다.

    1. // 클래스 템플릿
    2. template<typename t>    // A
    3. class X {};
    4.  
    5. // 오버로드된 두 개의 함수 템플릿
    6. template<typename t>    // B
    7. void function(T t) {}
    8.  
    9. template<typename t>    // C
    10. void function(int i, T t) {}


    위 템플릿들처럼 특수화되지 않은 템플릿들을 기본 템플릿이라고 한다. 기본 템플릿들은 특수화 될 수 있다.


    클래스 템플릿은 완전 / 부분 특수화가 모두 가능하나, 

    함수 템플릿은 완전 특수화만 가능하지, 부분 특수화는 불가능하다.

    그러나 함수 템플릿은 오버로드를 통해서 부분 특수화와 같은 효과를 얻을 수 있다.


    다음 코드들을 살펴보면서 규칙들을 자세히 확인해 보자.

    1. // 클래스 템플릿
    2. template<typename T>    // A
    3. class X {};
    4.  
    5. template<typename T>    // a-1. A의 포인터 형식에 대한 부분 특수화
    6. class X<T*> {};
    7.  
    8. template<>              // a-2. A의 int 타입에 대한 완전 특수화
    9. class X<int> {};
    10.  
    11. // 오버로드된 두 개의 함수 템플릿
    12. template<typename T>    // B
    13. void function(T t) {}
    14.  
    15. template<typename T>    // C
    16. void function(int i, T t, double d) {}
    17.  
    18. template<typename T>    // D. B와 C의 오버로드 함수. 이것은 부분 특수화가 아니다.
    19. void function(*t) {}
    20.  
    21. template<>              // b-1. B의 int 타입에 대한 완전 특수화
    22. void function<int>(int i) {}
    23.  
    24. void f(double d) {}     // B, C, D를 오버로드하는 일반 함수 (b-1은 오버로드하지 않는다)

    마지막으로, 함수 템플릿들의 여러 오버로드 버전들을 살펴보고 각각 어떤 상황에서 호출되는지 알아보자.
    오버로드 해소 규칙은 적어도 고수준에서는 상당히 단순하며, 전형적인 2 계급 시스템으로 표현할 수 있다.
    1. // 클래스 템플릿
    2. template<typename T>    // A
    3. class X {};
    4.  
    5. template<typename T>    // a-1. A의 포인터 형식에 대한 부분 특수화
    6. class X<T*> {};
    7.  
    8. template<>              // a-2. A의 int 타입에 대한 완전 특수화
    9. class X<int> {};
    10.  
    11. // 오버로드된 두 개의 함수 템플릿
    12. template<typename T>    // B
    13. void function(T t) {}
    14.  
    15. template<typename T>    // C
    16. void function(int i, T t, double d) {}
    17.  
    18. template<typename T>    // D. B와 C의 오버로드 함수. 이것은 부분 특수화가 아니다.
    19. void function(*t) {}
    20.  
    21. template<>              // b-1. B의 int 타입에 대한 완전 특수화
    22. void function<int>(int i) {}
    23.  
    24. void f(double d) {}     // B, C, D를 오버로드하는 일반 함수 (b-1은 오버로드하지 않는다)

    1. 비템플릿 함수들은 1급 시민이다.
    호출문과 일치하는 매개변수 형식들을 가진 보통의 함수와 템플릿 함수가 공존하는 경우 항상 보통 함수가 우선 선택된다.


    2. 호출과 최소한으로도 일치하는 1급 시민(일반 함수)가 없을 경우, 2급 시민이라 할 수 있는 기본 함수 템플릿들을 고려한다.
    그런 기본 함수 템플릿들이 여러 개 있는 경우(즉, 오버로드된 버전이 여럿 존재할 경우) 
    매개변수 형식들이 가장 잘 일치하며 "가장 구체적인" 것이 선택되는데, 이때 다음의 규칙들이 적용된다.

        2-1. "가장 구체적인" 기본 함수 템플릿이 하나만 있다면 그것이 선택된다.
        만일 그 기본 템플릿이 주어진 매개변수 형식들에 특수화된 것이라면, 그 특수화 버전이 선택되며,
        그렇지 않으면 주어진 매개변수들에 맞는 템플릿 인스턴스가 만들어진다.

        2-2. "가장 구체적인" 기본 함수 템플릿들이 여러 개인 경우 어느 것이 더 적한한지 컴파일러가 판단할 수 없으므로, 
        호출은 '애매한' 것이 된다.
        프로그래머는 어떠한 것을 호출하고자 하는지 좀 더 명시적으로 지정해야 한다.

    즉, 정리하면, 다음 순서라는 것이다.

    일반 함수  >>>  기본 함수 템플릿 >>> 오버로드 해소  >>>  특수화 함수 템플릿

    결단코 특수화된 함수 템플릿은 기본 함수 템플릿들과 나란히 우선 순위를 비교당할 수 없다.
    기본 함수 템플릿 선에서 먼저 어떠한 녀석이 선택되어진 이후에나, 
    그 기본 함수 템플릿을 특수화한 녀석들 중에서 가장 가까운 녀석을 찾는 것이다.

    위와 같이 오버로드와 특수화의 우선 순위가 정해진 데에는 핵심적인 이유가 있다.
    "특수화는 오버로드 되지 않는다"
    "오버로드는 일반 함수 또는 기본 함수 템플릿들에 대해서만 적용된다"
    "따라서, 오버로드 해소 단계에서는 특수화 함수 템플릿은 전혀 고려되지 않는다" 



    1. bool b;
    2. int i;
    3. double d;
    4.  
    5. f(b);        // B가 호출됨. B로 오버로드 해소가 되었고, T는 bool이 된다.
    6. f(i, 42, d); // C가 호출됨. C로 오버로드 해소가 되었고, T는 int가 된다.
    7. f(&i);       // D가 호출됨. D로 오버로드 해소가 되었고, T는 int가 된다.
    8. f(i);        // b-1이 호출됨. B로 오버로드 해소가 되었고, 그 중 특수화된 b-1이 선택됨.
    9. f(d);        // double 타입의 일반 함수가 존재하므로, 당연히 1순위.


    다시 한번 얘기하지만, 특수화된 함수 템플릿은 기본 함수 템플릿이 결정된 이후에나 우선 순위를 따져볼 수 있다.


    '@ 16. 1 ~ 17. 1 > 면접관련' 카테고리의 다른 글

    void 형 포인터  (0) 2017.01.04
    문자열 관련  (0) 2017.01.04
    C++ 정리(게임개발자를 위한 C++ 참고)  (0) 2016.12.28
    3D 좌표, 투영관련  (0) 2016.12.21
    포트폴리오 예상질문  (0) 2016.12.16
Designed by Tistory.