본문 바로가기
프로그래밍/c++

템플릿 기초

by 오늘의논리 2023. 3. 4.
728x90

템플릿 : 함수나 클래스를 찍어내는

  1. 함수 템플릿
  2. 클래스 템플릿

 

 

  1. 함수 템플릿
template<typename T>

void Print(T a)
{
	cout << a << endl;
}


int main()
{
    Print(50);
    Print(50.0f);
    Print(50.0);
    Print("Hello World");

	return 0;
}

template<typename T>// T 아니어도됨

template<class T> //동일

사용하면

void Print(int a), void Print(float a) 

각기 다른 버전의 Print 함수가 컴파일될때 생성됨

 

이때 메인에서

int main()
{
    Print<int>(50);
    Print(50.0f);
    Print(50.0);
    Print("Hello World");

	return 0;
}

 

저런식으로 <타입> 넣게되면 해당 버전으로 호출하게됨

Print<int>(50.0f); 이렇게하면 50.0f 여도 int 버전을 호출

 

만약

 

int Add(int a, int b)
{
	return a + b;	
}

float Add(float a, float b)
{
	return a + b;
}

 

 

이런 함수를 호출한다고 한다면

 

template<typename T>
T Add(T a, T b)
{
	return a + b;
}

int main()
{
    int result = Add(1, 2);
    float result2 = Add<float>(1.2f,1.2f);
    
	return 0;
}

 

이렇게 템플릿을 사용해서 간편하게 할수 있음

 

또한

인자를 두개 받는데 타입이 서로 다르다고 한다면

 

template<typename T1, typename T2 >
void Print(T1 a, T2 b)
{
	cout << a <<" "<<b<< endl;
}

 

 

이렇게하면 a,b 서로 다른타입이어도 생성됨

 

class Knight
{
public:

public:
	int _hp = 100;

};

template<typename T>
void Print(T a) // 각기 다른 버전의 Print 함수가 컴파일될때 생성됨
{
	cout << a << endl;
}

//템플릿 특수화
template<>
void Print(Knight k)
{
    cout << "Knight!!!!!" << endl;
    cout << k._hp << endl;
}





//연산자 오버로딩(전역함수 버전)
ostream& operator<<(ostream& os, const Knight& knight)
{
    os << knight._hp;
    return os;
}

int main()
{
    Knight k1;
    Print(k1);

	return 0;
}

그냥 Print 함수에 Knight 클래스를 넣는다고 하면 작동하지 않지만

연산자 오버로딩을 만들게되면 정상적으로 컴파일하게되고

추가로 만약 매개변수에 Knight 들어왔을때 특별한 함수로 들어오게 하고싶다면 템플릿 특수화를 통해 Knight 들어왔을때 호출할 있는 특별한 함수를 만들어 줄수 있음

 

 

클래스 템플릿

 

 

typename T(T는 변경가능)을 붙이면 '조커카드'(어떤 타입도 다 넣을 수 있음)

그런데 무조건 typename을 붙여야 하는 것은 아니다.

 

template<typename T>
class RandomBox
{
public:
    T GetRandomData()
    {
        int idx = rand() % 10;
        return _data[idx];
    }
public:
	T _data[10];

};


int main()
{
	srand(static_cast<unsigned int>(time(nullptr)));
    RandomBox<int> rb1;

    for (int i = 0; i < 10; i++)
    {
        rb1._data[i] = i;
    }

    int value1 = rb1.GetRandomData();
    cout << value1 << endl;

    RandomBox<float> rb2;

    for (int i = 0; i < 10; i++)
    {
  	  rb2._data[i] = i+0.5f;
    }

    float value2 = rb2.GetRandomData();
    cout << value2 << endl;


	return 0;
}

 

 

 

여기서 크기도 미리 정하지 않아도 된다

 

template<typename T, int SIZE>
class RandomBox
{
public:

    T GetRandomData()
    {
        int idx = rand() % 10;
        return _data[idx];
    }

public:
	T _data[SIZE];

};

 

이렇게 선언도 가능

template< >안에 들어가는건 [골라줘야 하는 목록] 이라고 있음

결국

 

int main()
{
    srand(static_cast<unsigned int>(time(nullptr)));

    RandomBox<int, 10> rb1;

    for (int i = 0; i < 10; i++)
    {
    	rb1._data[i] = i;
    }

    int value1 = rb1.GetRandomData();
    cout << value1 << endl;

    RandomBox<int,20> rb2;


    for (int i = 0; i < 20; i++)
    {
  	  	rb2._data[i] = i+0.5f;
    }
    
    int value2 = rb2.GetRandomData();
    cout << value2 << endl;

    return 0;

}

 

이렇게 SIZE 부분에 다른숫자가 들어가서 선언되면 RandomBox 1 2 전혀 다른 클래스로 만들어지게
rb1 = rb2; 성립하지 못하게됨

 

함수 템플릿에 나왔던 것처럼

 

//템플릿 특수화
template<int SIZE>
class RandomBox<double, SIZE>
{
public:

double GetRandomData()
{
    int idx = rand() % 10;
    return _data[idx];
}
public:
	double _data[SIZE];

};

 

double 버전이 호출될시 아래 RandomBox 실행되는것

 

728x90

'프로그래밍 > c++' 카테고리의 다른 글

vector #1  (0) 2023.03.04
콜백함수  (0) 2023.03.04
함수객체  (0) 2023.03.04
함수 포인터  (0) 2023.03.04
vector 기능 구현해보자  (0) 2023.03.04

댓글