템플릿(Temlpate) 정리
- 프로그래밍/STL
- 2011. 3. 25. 12:00
템플릿 총정리
1. 제네릭 프로그래밍(Generic Programming
- 절차,객체지향프로그래밍과는 다른 개념의 프로그래밍 패러다임중 하나로 일반화 프로그래밍이란것이 있다.
- 소프트웨어 라이브러리의 효율성과 재사용성을 높이려는 프로그래밍 패러다임의 하나
- 데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있는 기술에 중점을 두는 프로그래밍 방식
- 함수나 클래스 등의 프로그램 내 중요한 각 요소를 일반화
2. 템플릿(Template)이란?
- 무엇인가를 만들 때 안내역할을 하는데 사용되는 형식(꼴), 틀 또는 모형 등을 의미
- 특정 단위코드의 기본으로 사용될 수 있는 일반적인 클래스나 단위 원시코드
- C++ 표준 라이브러리
- 우리가 사용하는 템플릿의 의미는 타입의 상관없이 사용하기위해서 씀!!
- 컴파일러 입장에선 미리 함수의 형틀을 기억해 두었다가 함수가 호출될 떄 실제 함수를 만드는 장치!
(매크로함수와는 다르다) (메모리는 절약이 될까? => No 복사한것과 똑같이 잡아먹는다)
- 우리가 사용하는 템플릿의 의미는 타입의 상관없이 사용하기위해서 씀!!
- 컴파일러 입장에선 미리 함수의 형틀을 기억해 두었다가 함수가 호출될 떄 실제 함수를 만드는 장치!
(매크로함수와는 다르다) (메모리는 절약이 될까? => No 복사한것과 똑같이 잡아먹는다)
- 전역으로 선언되야함
( 밑의 내용을 공부하고 다시 봐라!!! )
템플릿의 원리!!!
- 전역으로 선언되어야함(주의할점)
- 함수 템플릿, 클래스 템플릿은 그냥 하나의 틀에 지나지 않는다.
즉, 그냥 템플릿 선언이기떄문에 메모리 할당과 구체화되어지지 않은 상태이다
- 함수 템플릿이 템플릿 함수로 구체화될때 각 타입마다 메모리할당하고 구체화되는식이다.
그래서 메모리를 적게 잡아먹는것이 아니다.
-구체화 되는 시기는 컴파일러가 <double>max( d1, d2 ) 이런식의 문형이 나왔을때 메모리할당과
구체화가 진행되는 식이다!!!! ㅇㅋ?!!?
이 원리를 이해했으면 템플릿은 끝!!!!!!!
3. 함수 템플릿
3.1)함수 템플릿이란?
- 뒤에 강세를 주어서 읽자 템플릿이다!!
3.1)함수 템플릿이란?
- 뒤에 강세를 주어서 읽자 템플릿이다!!
- 함수 템플릿은 다양한 템플릿 인자에 대한 함수군을 정의 한 것이다.
- 컴파일러는 함수 템플릿 정의문으로부터 앞으로 만들어질 함수의 모양만 기억하며 실제 함수가 호출될때 맞는 함수를 작성.
- 함수 템플릿으로부터 함수를 만드는 과정을 구체화, 인스턴스화라고 함
- 함수템플릿으로부터 구체화된것을 템플릿 함수라고함!!!!
- 컴파일러는 함수 템플릿 정의문으로부터 앞으로 만들어질 함수의 모양만 기억하며 실제 함수가 호출될때 맞는 함수를 작성.
- 함수 템플릿으로부터 함수를 만드는 과정을 구체화, 인스턴스화라고 함
- 함수템플릿으로부터 구체화된것을 템플릿 함수라고함!!!!
[ 형식 ]
template<템플릿인수1, 템플릿인수2..> 함수의 정의
Ex)
template <class T> void Func(T arg) {...}
template <typename T> void Func(T arg) {...}
=> <>괄호안에 class 또는 typename 둘다 가능하지만 웬만하면 typename을 쓰도록 하자!!
template <typename T> void Func(T 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)
특수화는 여러가지 형태가 존재한다
왜냐하면 표준화가 늦게 되서 ㅠㅜㅠㅠㅠ(안습)
1. template<> int S1Sizeof(const char* a)
2. template<> int S1Sizeof<>(const chat* a)
3. template<> int S1Sizeof<char*>(const char* a)
-여기서 <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-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
에서 참조좀 했음
추가한 내용:
함수 템플릿, 클래스 템플릿 구체화될때 주의점!
함수 템플릿은 형지정 안하고 그냥해도 암시적변환이되지만 클래스 템플릿은 반드시 형지정을 해줘야한다!
이유는 메모리 할당될때 형지정을 안해주면 객체자체로 인식하여 메모리할당하기떄문이다!!!
이 글을 공유하기