(전체가 아니라 C#과 차이가 있는 부분을 중심으로 요약 정리)

템플릿 매개변수에 대한 심화 학습

(생략)

클래스 템플릿 부분 특수화

(생략)

오버로딩으로 함수 템플릿 부분 특수화 흉내내기

(생략)

템플릿 재귀

C++의 템플릿은 단순히 클래스나 함수를 정의하는 것보다 많은 일을 할 수 있는데, 그중 하나가 템플릿 재귀(template recursion)이다. 구체적인 구현 방법을 살펴보기 전에 먼저 템플릿 재귀가 필요한 이유를 알아보자.

N차원 Grid: 첫 번째 시도

지금까지 본 Grid 템플릿은 2차원까지만 지원해서 활용 범위가 제한됐다. 예컨대 3D 틱택토나 4차원 행렬을 계산하는 수학 프로그램을 구현할 수 없다. 물론 원하는 차원마다 템플릿이나 클래스를 새로 만들어도 되긴 하지만 이러면 코드가 중복된다.

또 다른 방법은 일차원 Grid만 만들어두고, 이 Grid를 원소의 타입으로 갖는 Grid를 인스턴수화 하는 방식으로 원하는 차원에 대한 Grid를 만들 수 있다. 이떄 상위 Grid의 원소로 사용하는 일차원 Grid는 실제 원소의 타입으로 인스턴스화 한다. 다음 코드는 OneDGrid 클래스 템플릿의 구현코드를 보여준다.

template<typename T>
class OneDGrid
{
  public:
    explicit OneDGrid(size_t size = kDefaultSize);
    virtual ~OneDGrid() = default;

    T& operator[](size_t x);
    const T& operator[](size_t x) const;

    void resize(size_t newSize);
    size_t getSize() const { return mElements.size(); }

    static const size_t kDefaultSize = 10;

  private:
    std::vector<T> mElements;
};

template<typename T>
OneDGrid<T>::OneDGrid(size_t size)
{
  resize(size);
}

template<typename T>
void OneDGrid<T>::resize(size_t newSize)
{
  mElements.resize(newSize);
}

template<typename T>
T& OneDGrid<T>::operator[](size_t x)
{
  return mElements[x];
}

template<typename T>
const T& OneDGrid<T>::operator[](size_t x) const
{
  return mElements[x];
}

이렇게 구현한 OneDGrid를 이용해서 다음과 같이 다차원 그리드를 만들 수 있다.

OneDGrid<int> singleDGrid;
OneDGrid<OneDGrid<int>> twoDGrid;
OneDGrid<OneDGrid<OneDGrid<int>>> threeDGrid;
singleDGrid[3] = 5;
twoDGrid[3][3] = 5;
threeDGrid[3][3][3] = 5;

이렇게 해도 사용하는데 문제는 없지만 선언하는 부분이 좀 지저분하다. 다음 절에서 좀 더 개선해 보자.

진정한 N차원 Grid

템플릿 재귀를 활용하면 진정한 N차원 그리드를 구현할 수 있다. 다음 선언문에서 보듯이 그리드의 치원은 본질적으로 재귀적인 속성이 있기 때문이다.

OneDGrid<OneDGrid<OneDGrid<int>>> threeDGrid;

여기서 각각의 OneDGrid를 재귀의 한 단계로 볼 수 있다. int에 대한 OneDGrid는 재귀의 베이스 케이스 역할을 한다. 다시 말해 3차원 그리드는 int에 대한 일차원 그리드에 대한 일차원 그리드에 대한 일차원 그리드다. 이때 재귀 문장을 길게 나열할 필요 없이 다음과 같이 작성하면 알아서 N차원 그리드로 풀어서 써 준다.