본문 바로가기
Programing_Language/C++

템플릿(Template) (1/2)

by neohtux 2020. 12. 13.
728x90

템플릿(template)

  • C++에서 언어 차원에서 객체지향 프로그래밍 뿐만 아니라 제네릭 프로그래밍(generic programming)도 지원한다.
    제네릭 프로그래밍은 데이터를 중요시하는 객체지향적 프로그래밍 철학보단 알고리즘에 그 중점을 두었다.


    • 템플릿(template)은 데이터 타입(data type)이 아닌
      매개변수의 타입에 따라 클래스를 생성하는 클래스 템플릿메서드 템플릿, C++14 이후 부터는 변수 템플릿 이 있다.


    • 또한 템플릿은 템플릿 특수화라 하여 범위에 따라 다르게 템플릿을 적용시키는 템플릿 특수화 라는 개념이 있다.

      • 함수 템플릿 특수화
      • 클래스 템프릿 특수화
      • 포인터에 대한 특수화
  • 템플릿에 의한 형변환은 컴파일 타임에 결정된다. 즉 사람이 타입을 맞춰줄 필요없이 컴파일러에게 타입 결정하기를 시킨다.


  • 아래 예에서 각각의 템플릿을 보고 이해 하자.


함수 템플릿


템플릿을 적용시키지 않은 코드

//템플릿을 적용시키지 않은 코드의 예

int getMax(int a, int b)
{
    return (a > b) ? a : b;
}
char getMax(char a, char b)
{
    return (a > b) ? a : b;
}
double getMax(double a, double b)
{
    return (a > b) ? a : b;
}


int main(void)
{
  cout << getMax(2, 3) << '\n';
  cout << getMax(3.14, 1.592) << '\n';
  cout << getMax('a', 'c') << '\n';

  return 0;
}

템플릿을 적용시킨 코드

template<typename T>
T getMax(T x, T y)
{
    return (x > y) ? x : y;
}

int main(void)
{
  cout << getMax(2, 3) << '\n';
  cout << getMax(3.14, 1.592) << '\n';
  cout << getMax<char>('a', 'c') << '\n';

  return 0;
}
  • 템플릿을 적용 시킨 코드를 보면 알 수 있듯 template <typename T> 을 지정하여
    함수 내 반환 및 매개변수 타입을 T로 받아 컴파일러에게 형변환을 시킬 수 있다.
    또한 코드 라인을 보면 반복되는 부분의 재사용성을 증가시켜주는 것을 알 수 있다.




클래스 템플릿

위의 템플릿 타입변수 T를 사용하여 클래스에 적용시켜 보자.

 Myarray.h 파일
 template<typename T>
class MyArray
{
private :
    int m_length;
    T* m_data;

public :

    MyArray()
    {
        m_length = 0;
        m_data = nullptr;
    }

    MyArray(int length)
    {
        m_length = length;
        m_data = new T[length];
    }

    ~MyArray()
    {
        delete[] m_data;
        m_data = nullptr;
    }

/*  [] 연산자를 재정의 하여 값의 범위를 검사해주고,
**  배열내 인덱스에 위치한 값을 반환해준다.
**  반환 타입은 T&로 기본 데이터 타입에 상관없이
**  int, char, double 같은것이 와도 반환 할 수 있다.
*/
T& operator[](int index)
    {
        assert(index >= 0 && index < m_length);
        return m_data[index];
    }

    int getLength() { return m_length; }

// 해당 객체내 데이터(m_data)배열의 원소들을 출력한다.
    void print()
    {
        using namespace std;
        for (int i = 0; i < m_length; ++i)
            cout << m_data[i] << ' ';

        cout << '\n';
    }
};

MyArray.cpp 파일 (main문)

#include "MyArray.h"
int main()
{
  // char형 배열을 생성.
    MyArray<char> my_arr(10);

    //a(아스키 65)부터 10개를 대입 및 출력(print())
    for (int i = 0; i < my_arr.getLength(); ++i)
        my_arr[i] = i + 65;

    my_arr.print();

// int형 배열을 생성
    MyArray<int> my_IntegerArr(10);

    //1~10까지 대입 및 출력(print())
    for (int i = 0; i < my_IntegerArr.getLength(); ++i)
        my_IntegerArr[i] = i + 1;

    my_IntegerArr.print();
    return 0;
}


auto와 template의 차이점

  • C++14부터는 auto를 함수의 return 타입과 람다의 인자에서도 사용이 가능한데 이 때는 braced initializer를 std::initializer_list형으로 인식하지 못한다.

  • 즉 아래 두 가지 경우에 대해서는 (auto 타입 추론이 아닌) 템플릿 타입 추론 을 한다.

  // auto 타입 추론
 auto arr = { 1, 2, 3 }; // arr 타입은 std::initializer_list형으로 추론됨


 // template 타입 추론
 template
 void f(T arr);

 f({ 1, 2, 3 }); // Error. 이니셜라이저 리스트 타입 추론이 안된다.

auto는 또한 C++14에서 return 값으로 {1,2,3} 타입 추론이 안된다.

 auto func()
 {
   return {1,2,3}; // Error.
 }
300x250

댓글