728x90

기본적으로 템플릿은 편의성과 확장성을 모두 만족할 수 있는 기법입니다. 예를 들어 매개변수로 전달받은 두 수를 더하는 함수를 만든다고 가정했을 때 매개변수는 정수형이 올 수도 실수형이 올 수도 있습니다. 이럴 때 함수 오버로딩을 통해 각 매개변수 타입에 대한 함수를 다중 정의할 수 있습니다.

int Add(int a, int b);
double Add(double a, double b);

만약 간단하지 않은 하나의 함수를 여러가지로 다중 정의했을 때 문제가 발생하는 경우 모든 함수를 고치거나 손봐야 하는 경우가 생깁니다. 이럴 경우 사용할 수 있는 것이 템플릿입니다. 템플릿은 아래와 같이 template이라는 키워드를 사용합니다. 이렇게 정의한 코드를 사용자가 호출하면 컴파일러에 의해 다중 정의 코드가 자동으로 만들어지게 됩니다.

template <typename T>
T Add(T a, T b);

 사용자는 호출할 때 자료형을 명시해도 되고 안해도 됩니다.

#include <iostream>
using namespace std;

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

int main()
{
  cout << Add(3,4) << endl;
  cout << Add(3.3, 4.4) << endl;
  cout << Add<int>(3,4) << endl;
  cout << Add<int>(3.3, 4.4) << endl;
}

만약 위와 같이 자료형을 명시한다면 매개변수에 다른 타입을 넣어도 그 자료형에 맞게 캐스팅됩니다.

이 템플릿을 함수뿐 아니라 템플릿에도 적용이 가능합니다. 함수에서 사용하던 것과 다른 점이 있다면 무조건 타입을 명시해 주어야 합니다.

#include <iostream>
using namespace std;

template <typename T>
class valueSave {
public:
  valueSave(T value) : m_value(value) {}
  T getValue() { return m_value; }
private:
  T m_value;
};

int main()
{
  valueSave<int> vInt(10);
  cout << vInt.getValue() << endl;

  valueSave<double> vDouble(11.11);
  cout << vDouble.getValue() << endl;

  valueSave<int> vCast(13.13);
  cout << vCast.getValue() << endl;
}

템플릿을 사용하는 클래스의 선언과 정의를 분리하기 위해서는 아래와 같이 사용합니다.

template <typename T>
class valueSave {
public:
  valueSave(T value) : m_value(value) {}
  T getValue();
private:
  T m_value;
};

template <typename T>
T valueSave<T>::getValue()
{
  return m_value;
}

템플릿을 다중으로 사용할 수 있으며 그리고 템플릿으로 받는 값을 하나의 매개변수로도 사용할 수 있습니다.

#include <iostream>
using namespace std;

template <typename T, int nSize>
class valueSave {
public:
  valueSave(T value) : m_value(value) {}
  T getValue();
  void printSize() { cout << nSize << endl; }
private:
  T m_value;
};

template <typename T, int nSize>
T valueSave<T, nSize>::getValue()
{
  return m_value;
}

int main()
{
  valueSave<int, 3> vInt(10);
  cout << vInt.getValue() << endl;
  vInt.printSize();
}

이 템플릿의 타입과 값을 디폴트로 설정할 수 있습니다.

#include <iostream>
using namespace std;

template <typename T = int, int nSize = 5>
class valueSave {
public:
  valueSave(T value) : m_value(value) {}
  T getValue();
  void printSize() { cout << nSize << endl; }
private:
  T m_value;
};

template <typename T, int nSize>
T valueSave<T, nSize>::getValue()
{
  return m_value;
}

int main()
{
  valueSave<> vInt(10);
  cout << vInt.getValue() << endl;
  vInt.printSize();
}

템플릿을 사용하면 자료형에 상관없이 함수를 재사용할 수 있다는 장점이 있지만 만약 특정 자료형은 다르게 처리해야 하는 경우도 있습니다. 함수에서 이를 이용하기 위해서는 반환형, 매개변수 타입이 모두 같아야 합니다.

#include <iostream>
using namespace std;

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

template <>
char Add(char a, char b) 
{
  cout << "char template" << endl;
  return 'c';
}

int main()
{
  cout << Add<int>(3,4) << endl;
  cout << Add<double>(3.3, 4.4) << endl;
  cout << Add<char>('a','b') << endl;
}

 물론 클래스 템플릿에서도 사용할 수 있습니다. 하지만 클래스를 선언할 때 특수화할 클래스에 타입을 명시해 주어야 합니다.

#include <iostream>
using namespace std;

template <typename T>
class valueSave {
public:
  valueSave(T value) : m_value(value) {}
  T getValue() { return m_value; }
private:
  T m_value;
};

template <>
class valueSave<char> {
public:
  valueSave(char value) : m_value(value) {}
  char getValue() {
    cout << "Char Class" << endl;
    return m_value; 
  }
private:
  char m_value;
};

int main()
{
  valueSave<int> vInt(10);
  cout << vInt.getValue() << endl;

  valueSave<char> vChar('A');
  cout << vChar.getValue() << endl;
}

템플릿 특수화된 클래스에서 선언부와 정의부를 분리할 때는 따로 template <>을 기술하지 않아도 됩니다.

#include <iostream>
using namespace std;

template <typename T>
class valueSave {
public:
  valueSave(T value) : m_value(value) {}
  T getValue() { return m_value; }
private:
  T m_value;
};

template <>
class valueSave<char> {
public:
  valueSave(char value) : m_value(value) {}
  char getValue();
private:
  char m_value;
};

char valueSave<char>::getValue()
{
  cout << "Char Class" << endl;
  return m_value; 
}

int main()
{
  valueSave<int> vInt(10);
  cout << vInt.getValue() << endl;

  valueSave<char> vChar('A');
  cout << vChar.getValue() << endl;
}

 

728x90

'Programming > C++' 카테고리의 다른 글

[C++] boost windows 비동기 처리하기  (2) 2023.10.23
[C++] Template(2)  (0) 2023.09.22
[C++] std::forward_list, std::list  (0) 2023.07.18
[C++] std::array, std::vector  (0) 2023.07.12
[C++] 람다 함수  (0) 2023.04.07

+ Recent posts