템플릿(Temlpate) 정리

템플릿 총정리
 

1. 제네릭 프로그래밍(Generic Programming 

-  절차,객체지향프로그래밍과는 다른 개념의 프로그래밍 패러다임중 하나로 일반화 프로그래밍이란것이 있다.
- 소프트웨어 라이브러리의 효율성과 재사용성을 높이려는 프로그래밍 패러다임의 하나
- 데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있는 기술에 중점을 두는 프로그래밍 방식
- 함수나 클래스 등의 프로그램 내 중요한 각 요소를 일반화
 


 

 
2. 템플릿(Template)이란?
- 무엇인가를 만들 때 안내역할을 하는데 사용되는 형식(꼴), 틀 또는 모형 등을 의미
- 특정 단위코드의 기본으로 사용될 수 있는 일반적인 클래스나 단위 원시코드
- C++ 표준 라이브러리
- 우리가 사용하는 템플릿의 의미는 타입의 상관없이 사용하기위해서 씀!!
- 컴파일러 입장에선 미리 함수의 형틀을 기억해 두었다가 함수가 호출될 떄 실제 함수를 만드는 장치!
(매크로함수와는 다르다) (메모리는 절약이 될까? => No 복사한것과 똑같이 잡아먹는다)
- 전역으로 선언되야함



 

( 밑의 내용을 공부하고 다시 봐라!!! )

템플릿의 원리!!!
- 전역으로 선언되어야함(주의할점)
- 함수 템플릿, 클래스 템플릿은 그냥
하나의 틀에 지나지 않는다.
   즉, 그냥 템플릿 선언이기떄문에 메모리 할당과 구체화되어지지 않은 상태이다
- 함수 템플릿이 템플릿 함수로 구체화될때 각 타입마다 메모리할당하고 구체화되는식이다.
그래서 메모리를 적게 잡아먹는것이 아니다.

-구체화 되는 시기는 컴파일러가 <double>max( d1, d2 ) 이런식의 문형이 나왔을때 메모리할당과
구체화가 진행되는 식이다!!!! ㅇㅋ?!!?

이 원리를 이해했으면 템플릿은 끝!!!!!!! 


 
3. 함수 템플릿

3.1)함수 템플릿이란?
-
뒤에 강세를 주어서 읽자 템플릿이다!! 
- 함수 템플릿은 다양한 템플릿 인자에 대한 함수군을 정의 한 것이다.
- 컴파일러는 함수 템플릿 정의문으로부터 앞으로 만들어질 함수의 모양만 기억하며 실제 함수가 호출될때 맞는 함수를 작성.
- 함수 템플릿으로부터 함수를 만드는 과정을 구체화, 인스턴스화라고 함
- 함수템플릿으로부터 구체화된것을 템플릿 함수라고함!!!!
 

[ 형식 ]
    template<템플릿인수1, 템플릿인수2..> 함수의 정의
Ex)
    template <class T> void Func(T arg) {...}
    template <typename T> void Func(arg) {...}                    

=> <>괄호안에 class 또는 typename 둘다 가능하지만 웬만하면 typename을 쓰도록 하자!!



3.2)함수 템플릿의 특수화
 특수한 경우를 미리 선언하여 컴파일러에게 알려주는것을 함수 템플릿의 특수화라고함
 template<> 이런식으로 씀!
 
 ex)   S1Sizeof()함수가 기본으로 sizeof()로 리턴하는 함수 템플릿이라고 가정하면
문자열길이 strlen()으로 리턴해주고싶다!! => 이럴때 템플릿 특수화를 씀

함수 템플릿 특수화 예제) 
template<>
int S1Sizeof( const char* a )
{
        return ( strlen(a) );
}


주의! 
위의 예제는 당연히 전역으로 선언되야함!
template<> 는 특수화이기때문에 기본형태를 위에서 반드시 취하고 있어야한다!!!!!!!!!!!!!!!

이유는? 
기본형태가 없이 독립적으로 template<> 만 쓰게 되면 컴파일러가 알 수 없다!!
그러므로 위의 예제는 컴파일에러가 날것임..(공부를위해 그냥 쓴것임)

특수화는 여러가지 형태가 존재한다
왜냐하면 표준화가 늦게 되서 ㅠㅜㅠㅠㅠ(안습)
1. template<> int S1Sizeof(const char* a)
2. template<> int S1Sizeof<>(const chat* a)
3. template<> int S1Sizeof<char*>(const char* a)
 

3.3)함수 템플릿 특징 
-여기서 <typename T> 라는것은 템플릿 인수 리스트라고 불린다.
- 템플릿 인수 리스트는 인자형을 대신할 변수들을 의미하며 위의 예에서 class는 단지 템플릿인자임을 나타내는 기호이고 클래스를 나타내는 것과는 성격이 다르다.(그런의미에서 typename이라는 키워드를 사용하도록 권장)
- inline, static, extern등의 키워드들은 함수명 바로앞에 기술한다.
- 템플릿 인수리스트에 선언된 인자들은 최소한 1번 이상 쓰여야 한다. ( template Func() 는안된다. )
- 인수 리스트에는 수식, 함수등이 올 수도 있다.
- 템플릿함수와 일반함수가 중복되었을 경우에는 일반함수가 우선적으로 호출되어진다.
- 템플릿함수나 일반함수로도 생성될 수 없는  함수가 호출되면 에러가 발생한다.  
이러한 경우는 이 때의 함수 프로토타입다음을 선언하여 주면 된다.

 

template<class T, class T> T Func(T a, T b) { ... }
Func(1, 2.3);                     // 형이 다르므로 에러
 
template<class T, class T> T Func(T x, T y) { ... }
double Func(double, double);      // 템플릿 확장 (프로토타입 선언)
Func(3, 3.14);
 
// 자동 형변환에 의해 Func(double(3), 3.14)로 인식되어진다.



3.4)템플릿함수도 다형성이 적용된다.
 

*템플릿함수의 다형성
 
template<class T> T Func(T,T);
template<class T> T Func(T,T,int);



ex)템플릿함수을 왜 쓰는지 소스를 보고 이해해보자!!!

[max 함수의 표현]
short const& max( short const& a, short const& b )
{
    return a < b ? b : a;
}
 
int const& max( int const& a, int const& b )
{
    return a < b ? b : a;
}
 
double const& max( double const& a, double const& b )
{
    return a < b ? b : a;
}
 
std::string const& max( std::string const& a, std::string const& b )
{
    return a < b ? b : a;
}


===>>>>>>>
[max 함수를 템플릿으로 표현]
template <typename T>
T const& max( T const & a, T const& b )
{
    return a < b ? b : a;
}



[max 함수의 호출]
#include <iostream>
#include <string>
 
// function family definition
template <typename T>
T const& max( T const & a, T const& b )
{
    return a < b ? b : a;
}
 
int main( void )
{
    short s1 = 3;
    short s2 = 4;
    short s3 = ::max( s1, s2 );
    std::cout << s3 << "\n";

    int a = 3;
    int b = 4;
    int c = ::max( a, b );
    std::cout << c << "\n";       
   
   
    double d1 = 1.1f;
    double d2 = 2.2f;
    double d3 = ::max( d1, d2 );
    std::cout << d3 << "\n";
    std::string str1 = "나는 ";
    std::string str2 = "누구 ";
    std::string str3 = ::max( str1, str2 );
    std::cout << str3 << "\n";
    return 0;
}






 
 

 
4.클래스 템플릿
4-1). 클래스 템플릿
- 클래스가 여러개의 데이터형으로 바뀔 수 있는 것을 말한다.
- 즉 멤버 변수가 템플릿으로 지정되있는것을 클래스 템플릿이라고 한다.

 

[ 형식 ]
    template <템플릿인수1, 템플릿인수2..> 클래스의 정의{};
 
Ex)
    template<typename T>
    class SK {
        protected:
            int x, y;
            T z;
        public:
            SK(int a, int b, T c) {
            x = a; y = b; z = c;
        }
        void OUT(void) {
            gotoxy(x,y); cout << z; }
        } ;
               :

    
//사용하는 부분
    SK<int> var1(5, 5, 10);
    SK<char> var2(10, 10, 'A');
    SK<float> var3(15, 20, 3.14);
              :


- 인수리스트의 인수중에는 사용되지 않은 것이 존재해도 상관없다.
- 위의 보기와 같이 사용부분에서 < >사이에 사용자가 사용하고자 하는 자료형을 지정해 주어야 한다.
- 클래스 템플릿에서도 static멤버나 함수의 외부정의를 사용할 수 있다. 이러한 경우에는 다음과 같다.
 

template<class T>
class ACCESS {
    static int s;
    int x, y;
    T z;
};

template<class T> int ACCESS<T>::s=0; // static멤버의 정의
 
template<class T> ACCESS<T>::ACCESS(int a, int b, T c)   // 외부 정의 할때
{
    x = a;
    y = b;
    z = c;
}
 
//즉 외부 정의 할때도 템플릿은 꼭 명칭해줘야한다!!!



#include <vector>
#include <string>
 
class AB
{
public:
    int pop();
};
 
template <typename T>
class Stack
{
public:
    void push(T const & elem);
    T pop();

private:
    std::vector<T> elems;      // 요소
};
 
template <typename T>
void Stack<T>::push( T const & elem )
{
    elems.push_back( elem );
}
 
template <typename T>
T Stack<T>::pop()
{
    T elem = elems.back();
    elems.pop_back();
    return elem;
}
 
int main( void )
{
    Stack<int> intstack;
 
    intstack.push( 1 );
    intstack.push( 2 );
    intstack.push( 3 );
    intstack.push( 4 );
    intstack.push( 5 );
    intstack.push( 6 );
    intstack.push( 7 );
 
    Stack<std::string> stringstack;
 
    stringstack.push("abcdefg1");
    stringstack.push("abcdefg2");
    stringstack.push("abcdefg3");
    stringstack.push("abcdefg4");
    
    stringstack.pop();
    stringstack.pop();
    stringstack.pop();
    stringstack.pop();

    return 0;
}



4-2) 클래스 템플릿의 특수화
클래스 템플릿도 함수 템플릿과 마찬가지로 실제 클래스 타입이 사용될 때만 구체화된다. 만약 특정 타입에 대해 미리 클래스 선언을 만들어 놓을 필요가 있다면 명시적 구체화를 할 수 있다. 

template<> class 클래스명<특수타입>

 

이 선언에 의해 컴파일러는 클래스명<특수타입> 클래스를 미리 생성한다. 

 
그래서 특수화를 하면 특수화된 클래스는 객체를 선언하지 않더라도 자동으로 구체화된다.
클래스 템플릿의 부분 특수화라는것이 있다. (부분적으로만 특수화시키는방법) 

 


4-3). 클래스 템플릿의 부분 특수화
- 여러개의 템플릿 파라미터 중 부분적으로만 특수화를 하는 것
 

// 부분 특수화할 클래스
template <typename T1, typename T2>
class MyClass
{
    //...템플릿 T1, T2 안들어감
}; 
 
// 부분 특수화 : 두 템플릿 파라미터가 같은 데이터형을 가짐
template <typename T>
class MyClass<T, T>
{
    //...
};
 
// 부분 특수화 : 두번째 파라미터를 int 형으로 특수화 함
template <typename T>
class MyClass<T, int>
{
    //...
};
 
// 부분 특수화 : 두 파라미터가 포인터 형으로 특수화 함
template <typename T>
class MyClass<T*, T*>
{
    //...
};




4.4. 기본 템플릿 인자
- 템플릿 파라미터가 기본적으로 갖는 인자
- default parameter와 같은 개념
- 함수 템플릿에는 안되고 클래스 템플릿만 된다


// 기본 템플릿 인자의 예) 
// tip:재미있는 것으로 이전 템플릿 파라미터를 참조 할 수 있다.
 
template <typename T, typename CONT = std::vector<T> >    //디폴트 지정
class MyClass
{
    //...
};



// 기본 템플릿 인자의 예
#include <vector>
#include <list>
 
// 파라미터가 1개일 경우
template <typename T = char >
class PARAMETER_ONE
{
    // ...
};
 
// 파라미터가 2개일 경우
template <typename T, typename CONT = std::vector<T> >
class PARAMETER_TWO
{
    //...
};
 
int main( void )
{
    PARAMETER_ONE<> one_sample_1;                                //이렇게 <>만 줘도 디폴트 지정이 있기때문에 가능함
    PARAMETER_ONE<int> one_sample_2;                             //이건 당연히 가능
    PARAMETER_TWO< int, std::list<int> > two_sample_1;       //이건 당연히 가능
    PARAMETER_TWO<int> two_sample_2;                             //이렇게 해줘도 디폴트 지정이있어서 가능
 
    return 0;
}





템플릿함수에 대해서 정리 되있는것을 총정리함
http://blog.naver.com/islove8587?Redirect=Log&logNo=10025033292
서 참조좀 했음

추가한 내용:
함수 템플릿, 클래스 템플릿 구체화될때 주의점!
함수 템플릿은 형지정 안하고 그냥해도 암시적변환이되지만 클래스 템플릿은 반드시 형지정을 해줘야한다!
이유는 메모리 할당될때 형지정을 안해주면 객체자체로 인식하여 메모리할당하기떄문이다!!! 

이 글을 공유하기

댓글

Designed by JB FACTORY