Post

C++ - 템플릿

C++ 템플릿

1. 개요

코드는 같은데 자료형만 다른 것을 컴파일러가 만들어주는 것이다.
딱히, 성능에는 이득이 없고 개발자만 편한 기능이지만 이 기능은 매우 많이 사용되고 있다.

2. 템플릿 함수

템플릿 함수는 함수의 매개 변수 또는 구현에 사용되는 자료형을 결정하여 생성한다.
일반적으로는 {반환형} {함수 이름} ( {매개변수} ) { {함수 내용} }으로 선언 가능했던 함수 형태지만 함수 정의에서 template 혹은 template 를 추가한다. (class보단 typename을 좀 더 많이 쓰는 거 같긴한다)

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>
#include<typeinfo>

using namespace std;

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

template <typename T1, typename T2> T1 diffAddNumber(T1 a,T2 b) {
  return a+b;
}

위와 같이 선언된 템플릿 함수는 실제 사용될때 해당 자료형을 선언하여 쓰게된다.

1
2
3
4
5
6
7
8
int main() {
  // 명시적으로 자료형 선언
  auto test1 = addNumber<int>(5, 4);
  
  // 입력된 값의 자료형으로 template 자료형 결정
  auto test2 = addNumber(5, 3);
  auto test3 = diffAddNumber(5, 3.2);
}

만약 특정 데이터 타입에 대해서 다른 작업을 해야하는 경우 template <> 을 이용하여 해당 자료형에 대해서 다시 정의해야한다. 이를 템플릿 특수화라고 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
struct customType {
  int x;
  int y;
  int value;
}

template<typename T> void sort(std::vector<T>& vec){
  std::sort(begin(vec), end(vec));
}

template<> void sort(std::vector<customType>& vec) {
  std::sort(begin(vec), end(vec), [](customType& data1, customType& data2)->bool { return data1.value < data2.value;});
}

3. 템플릿 클래스

말 그대로 클래스를 템플릿으로 선언하는 것으로 각 자료형에 맞춰서 생성된다.
동일하게 typename에는 모든 종류의 자료형이 들어올 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
template <typename T>
class customContainer {
public:
    explicit customContainer(int size) { data_ = new T[size]; size_ = size; }
    virtual ~customContainer() { delete data; size_ = 0; }

    T& operator[](size_type idx) { return data_[idx]; }
    const T& operator[](size_type idx) const { return data_[idx]; }

private:
    T* data_;
    int size_type;
};

템플릿 클래스도 역시 클래스는 클래스이기 때문에 상속이 가능하며, 추가 자료형의 경우 별도로 정의하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <typename T>
class A {
public:
    T data;
    int data_1;
};


template <typename T, typename U>
class B : public A<T> {
public:
    U data_2;
    int data_3;
};

매개 변수 팩(parameter pack)

흡사 함수의 가변 매개변수와 같이, template의 자료형을 가변적으로 사용하는 방식이다.
기본적으로 모두 컴파일 타임에 처리되고 인라인 함수화 되기 때문에 성능에 영향은 없다.

일단 c++17 기준으로 사용법이 다르다. 따라서 아래의 코드를 실행시켜보고 사용해야한다.

1
2
3
4
5
6
7
8
9
#include <iostream>
using namespace std;

int main()
{
    cout << __cplusplus << endl;

    return EXIT_SUCCESS;
}

이 값이 201700 이하라면 아래와 같이 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <functional>

template<typename T>
T mult(T first) {
  return first;
}

template<typename T, typename... Args>
T mult(T first, Args... args) {
  return first * mult(args...);
}


using namespace std;

int main()
{
    cout << mult(1,2,3,4) << endl;

    function<int(int)> fn1 = mult<int>;
    cout << fn1(1) << endl;

    function<int(int, int, int, int)> fn2 = mult<int, int, int, int>;
    cout << fn2(1,2,3) << endl;

    return 0;
}

201700이상이라면 아래와 같이 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <functional>

template<typename... Args>
auto mult(Args... args)
{
    return (args * ...);
}
using namespace std;

int main()
{
    cout << mult(1,2,3,4) << endl;

    function<int(int)> fn1 = mult<int>;
    cout << fn1(1) << endl;

    function<int(int, int, int, int)> fn2 = mult<int, int, int, int>;
    cout << fn2(1,2,3) << endl;

    return 0;
}

참고자료

This post is licensed under CC BY 4.0 by the author.