KoreanFoodie's Study

Effective C++ | 항목 48 : 템플릿 메타프로그래밍, 하지 않겠는가? 본문

Tutorials/C++ : Advanced

Effective C++ | 항목 48 : 템플릿 메타프로그래밍, 하지 않겠는가?

GoldGiver 2022. 10. 25. 16:33

C++ 프로그래머의 필독서이자 바이블인, 스콧 마이어스의 Modern Effective C++ 를 읽고 기억할 내용을 요약하고 있습니다. 꼭 읽어보시길 추천드립니다!

항목 48 : 템플릿 메타프로그래밍, 하지 않겠는가?

핵심 :

1. 템플릿 메타프로그래밍은 기존 작업을 런타임에서 컴파일 타임으로 전환하는 효과를 낸다. 따라서 TMP 를 쓰면 선행 에러 탐지와 높은 런타임 효율을 손에 거머쥘 수 있다.
2. TMP 는 정책 선택의 조합에 기반하여 사용자 정의 코드를 생성하는 데 쓸 수 있고, 특정 타입에 대해 부적절한 코드가 만들어지는 것을 막는 데도 쓸 수 있다.

 

템플릿 메타프로그래밍(template metaprogramming: TMP) 는 컴파일 도중에 실행되는 템플릿 기반의 프로그램을 작성하는 일을 말한다.

TMP 는 두 가지 장점이 있다. 첫째, 까다롭거나 불가능한 일을 매우 쉽게 할 수 있고, 둘째, 런타임 부하를 줄여준다.

 

이제 항목 47에서 컴파일 문제가 일어난 부분을 다시 한 번 보자.

 

 

void advance(std::list<int>::iterator& iter, int d)
{
  if (typeid(typename std::iterator_traits<std::list<int>::iterator>::iterator_category)
    == typeid(std::random_access_iterator_tag))
  {
    iter += d;
  }
  ...
}

여기서 list 는 양방향 반복자를 가지므로, iter += d; 부분 자체가 불가능해 컴파일이 되지 않는다!

 

TMP 는 그 자체가 튜링 완전성을 갖고 있어, 어떤 것이든 계산할 수 있다(변수 선언, 루프, 함수 작성 및 호출 등).

TMP 의 루프는 재귀함수 호출을 만들지 않고 재귀식 템플릿 인스턴스화(recursive template instantiation)를 통해 진행된다. 예시를 보자.

#include <iostream>

template<unsigned n>
struct Factorial
{
  enum { value = n * Factorial<n-1>::value };
};

template<>
struct Factorial<0>
{
  enum { value = 1 };
};

int main()
{
  // 런타임 계산 없이 아래 값들을 출력
  std::cout << Factorial<5>::value << std::endl;
  std::cout << Factorial<10>::value << std::endl;
}

 

TMP 의 대표적인 쓰임처는 다음과 같다 :

  • 치수 단위(dimensional unit) 의 정확성 확인 : 컴파일 도중에 단위의 정합성이 체크된다
  • 행렬 연산의 최적화 : 덩치 큰 임시 객체를 없애고 루프를 병합한다
  • 맞춤식 디자인 패턴 구현의 생성 : 정책 기반 설계(policy-based design) 을 이용해 패턴을 조합. 생성식 프로그래밍(generative programming)의 기초가 이런 기술

TMP 의 더 자세한 예시는 C++ Beginner 카테고리의 9-3번 글과 9-4번 글을 참고하도록 하자!

Comments