[STL] 템플릿 Template

치치·2025년 2월 13일

STL

목록 보기
8/21
post-thumbnail

함수 템플릿

여러 함수를 만들어내는 함수의 틀

일반적으로 함수를 호출할때, 함수(인자,인자); 이런식으로 호출을 한다
만약 함수의 오버로딩을 사용한다면?

함수의 오버로딩 : 함수의 이름은 같지만, 들어오는 매개변수의 타입이 다른 것


ex) 함수의 오버로딩

  • 메인함수쪽에서 Print()함수를 호출하고 있다
    -> 클라이언트(호출하는 쪽)

  • 함수의 오버로딩 자체가 함수를 호출하는 쪽에서 매개변수의 타입을 미리 알고있다는 전제로 만들어진다
    -> 클라이언트가 함수의 매개변수 타입을 알고 그 타입에 맞는 값을 인자로 넣는다

  • 그렇기 때문에 만약 클라이언트에서 사용자 정의 타입(클래스)의 타입을 결정해야 할 경우 함수의 오버로딩은 사용할 수 없다

    이것이 템플릿을 사용하는 이유이다!
    템플릿 함수를 사용하면 컴파일러는 클라이언트 (호출하는 쪽)의 함수 호출 인자 타입을 보고 템플릿 함수의 매개변수 타입을 결정한다

#include <iostream>
using namespace std;

void Print(int a, int b)
{
    cout << a << "," << b << endl;
}

void Print(float a, float b)
{
    cout << a << "," << b << endl;
}

void Print(char a, char b)
{
    cout << a << "," << b << endl;
}


int main()
{
    Print(1, 2);
    Print(1.5f, 4.5f);
    Print('A', 'B');
}

출력값 :


함수 템플릿 사용방법

  1. 함수 앞에 template <typename T> 키워드를 붙인다

  2. T는 템플릿 매개변수이며 함수를 호출하는 쪽에서 결정한다 (자료형)

  3. 함수 템플릿 인스턴스 : 컴파일러가 생성한 함수 정의 코드
    -> 호출하는 타입을 매개변수로 하는 함수

  4. 타입에는 자료형 뿐 아니라 정수값도 들어올 수 있다
    -> 명시적 호출로만 가능하다

일반적인 호출방법

#include <iostream>
using namespace std;

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


int main()
{
    Print(1, 2);
    Print(1.5f, 4.5f);
    Print('A', 'B');
}

출력값 :


명시적 호출방법

  • 결과는 동일하다
  • 컴파일(실행)이 완료되면 함수 템플릿은 존재하지 않으며, 인스턴스화 된 3개의 함수만 남는다
    -> 즉, Print<int>(), Print<float>(), Print<char>() 함수가 만들어지고 함수 템플릿은 존재하지 않게됨


매개변수 2개 받는 템플릿 함수

  1. 함수 앞에 template <typename T1, typename T2> 키워드 붙이기



함수 템플릿 특수화 (Function Template Specialization)

'특정 타입'에 대해 다른 동작을 정의하고 싶을때 사용한다



ex) 만약 사용자 정의 타입의 연산을 하고싶을때

  • 아래 코드와 같이 사용자 정의 타입(클래스) 객체끼리의 연산을 하려면 연산자 오버로딩이 필요하다!

  • 컴파일러는 C++에서 정의된 연산만 가능하기 때문에, 클래스는 사용자가 정의해둔 것이기 때문에 연산이 불가능하다

  • 클래스 내부에 연산자 오버로딩을 사용하여 선언해주면 두 객체의 연산이 가능해진다

사용자 정의 연산자 오버로딩

오버로딩은 따로 정리해둔 블로그를 다시 보도록 하자
https://velog.io/@yangju058/STL-연산자-오버로딩

컴파일 에러 예제

정답 예제

#include <iostream>
using namespace std;


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

class MyClass 
{
public:
    int value;

    MyClass(int v)
    {
        this->value = v;
    }

    MyClass operator +(const MyClass& other)
    {
        return MyClass(value + other.value);
    }
};

int main() 
{


    MyClass obj1(10), obj2(20);
    
    MyClass result = obj1 + obj2;

    cout << result.value << endl;
}

함수 템플릿 특수화 사용방법

  1. 함수 위에 template<> 키워드 사용

  2. 매개변수로 사용자 정의타입을 받는다

  3. 안쪽에 사용자 정의 타입의 멤버 변수끼리의 연산 결과를 반환한다

#include <iostream>
using namespace std;


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

// MyClass에 대한 템플릿 특수화
template <>
MyClass add(MyClass a, MyClass b) 
{
    return MyClass(a.value + b.value);  // 명시적으로 더하기 연산 정의
}

class MyClass 
{
public:
    int value;
    MyClass(int v)
    {
        this->value = v;
    }
};

int main() 
{
    std::cout << add(3, 5) << std::endl;  // 일반 템플릿 사용

    MyClass obj1(10), obj2(20);
    MyClass result = add(obj1, obj2);  // 특수화된 함수 호출
    std::cout << "MyClass 결과: " << result.value << std::endl;
}
  • 일반 템플릿 함수에서 정수 값을 넣으면 결과가 나오는데,
    만약 클래스 객체를 인자값으로 넣으면 템플릿 특수화를 거쳐서 해당 객체의 멤버 변수끼리의 결과값이 나온다

함수 템플릿 사용이유

operator()로 정의해도 똑같이 객체끼리 연산할 수 있는데, 왜 템플릿 특수화를 사용할까?

  • 템플릿을 사용하면 어떤 타입이 들어오든 일반적인 연산을 수행할 수 있다

  • 근데, 특정 타입에서만 다르게 동작해야 한다면 템플릿 특수화를 사용하여 별도로 처리하는 것이 더 적절하다

  • 코드의 직관성을 높이고, 가독성이 좋기 때문이다



클래스 템플릿

여러 클래스를 만들어내는 클래스의 틀

형식 : template <typename T> 키워드를 붙이고, class 클래스 이름

앞에서 본 함수 템플릿과 거의 같다

템플릿 매개변수 인자를 통해 클라이언트가 클래스에 사용될 타입을 결정할 수 있다

클래스 템플릿도 마찬가지로, 컴파일러가 클래스 템플릿을 이용하여 실제 클래스(자료형 지정된걸로)를 생성한다

-> 기존 클래스 템플릿은 없어지고, 클래스 템플릿 인스턴스가 생성된다

  • 템플릿의 매개변수도 default값을 지정할 수 있다

클래스 템플릿 예제 코드

#include <iostream>
using namespace std;


template <typename T1 = int, typename T2 = int>
class Pair 
{
private:
    T1 first;
    T2 second;
public:
    Pair(T1 a, T2 b)
    {
        first = a;
        second = b;
    }

    void print() 
    {
        cout << "First: " << first << ", Second: " << second << endl;
    }
};

int main() 
{
    Pair<int, double> p1(10, 3.14);
    Pair<string, char> p2("Hello", 'A');

    Pair<>p3(10, 20); // 디폴트값 사용

    p1.print(); 
    p2.print(); 
    p3.print();

    return 0;
}


클래스 템플릿 특수화 (Class Template Specialization)

사용 형식 : template <> class 클래스 이름<매개변수 타입>

#include <iostream>
#include <string>
using namespace std;

// 일반 템플릿
template <typename T>
class Printer 
{
public:
    void print(T value) 
    {
        cout << "일반 템플릿: " << value << endl;
    }
};

//string에 대한 클래스 템플릿 특수화
template <>
class Printer<string> 
{
public:
    void print(string value) 
    {
        cout << "문자열 특수화: " << value << endl;
    }
};

int main() 
{
    Printer<int> intPrinter;
    Printer<string> stringPrinter;

    intPrinter.print(42);          
    stringPrinter.print("Hello!"); // 특수화된 템플릿 사용

    return 0;
}

profile
뉴비 개발자

0개의 댓글