Post List

2015년 1월 4일 일요일

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

 템플릿 메타프로그래밍(template metaprogramming: TMP)은 컴파일 도중에 실행되는 템플릿 기반 프로그램을 작성하는 일을 말한다. 즉 C++ 컴파일러가 실행시키는 C++로 만들어진 프로그램이다.

 TMP에는 엄청난 강점이 있다. 첫째, 다른 방법으로는 까다롭거나 불가능한 일을 굉장히 쉽게 할 수 있다. 둘째, C++ 컴파일이 진행되는 동안 실행되기 때문에, 런타임 영역에서 컴파일 타임 영역으로 작업 전환할 수 있다. 즉 프로그램 실행 도중에 잡혀 왔던 몇몇 에러들이 컴파일 도중에 찾을 수 있게 되었다. 또 실행 코드가 작아지고, 시간도 짧아지고, 메모리도 적게 잡아먹게 되었다.

 TMP의 동작 원리를 엿볼 수 있는 방법 중 가장 대표적인 것이 루프이다. TMP의 루프는 재귀 함수 호출을 만들지 않고 재귀식 템플릿 인스턴스화(recursive template instanitation)을 한다. 일반 프로그래밍의 시작은 "hello world" 이듯, TMP의 시작은 계승(Factorial)을 계산하는 템플릿이다.

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::cout << Factorial<10>::value;
}

 Code가 깔끔하게 이쁘지 않나 ? 더군다나 놀라운 사실은 위의 연산을 런타임에 하는게 아니라 컴파일 타임에 C++이 미리 다 해놓는다는 것이다. 그 와중 오류가 있다면 컴파일 오류로 남긴다.

 TMP가 실력 발휘하는 분야의 세가지 예를 들어보겠다.

 1. 치수 단위(dimensional unit)의 정확성 확인) : 과학기술 분야의 응용프로그램을 만들 때는 중요한 부분이다. 프로그램 안의 모든 치수 단위의 조합이 제대로 맞춰졌는지 컴파일 타임에 볼 수 있다.

 2. 행렬(Matrix) 연산의 최적화 : 행열에서 operator* 등의 연산은 큰 임시 행렬이 생겨야 하며 루프연산을 순차적으로 반복해야 한다. 표현식 템플릿(expression template)를 사용하면 덩치 큰 임시 객체를 없애는 것은 물론이고 루프까지 합쳐 버릴 수 있다. 이로서 메모리도 적게 먹으며 빛처럼 빠른 소프트웨어를 만들 수 있다.

 3. 맞춤식 디자인 패턴 구현의 생성 : 전략(Strategy) 패턴, 감시자(Observer) 패턴, 방문자(Visitor) 패턴 등 디자인 패턴 구현방법이 여러가지 일 경우 정책 기반 설계(policy-based design)을 사용하면 따로따로 마련된 설계상의 선택[ 보통 정책(policy)라고 부름 ] 을 나타내는 템플릿을 만들수 있다. 이렇게 만들어진 정책 템플릿은 서로 임의대로 조합되어 수백가지 타입 생성이 가능해진다. 이른바 생성식 프로그래밍(generative programming)의 기초가 되는 기술이다.

 하지만 TMP는 문법이 비직관적이고, 개발도구의 지원도 아주 미약하다. 즉 프로그래머 입장에서 아주 어렵다. ㅠㅠ

 * 템플릿 메타프로그래밍은 기존 작업을 런타임에서 컴파일 타임으러 전환하는 효과를 냅니다. 따라서 TMP를 쓰면 선행 에러 탐지와 높은 런타임 효율을 손에 거머쥘 수 있습니다.

 * TMP는 정채 선택의 조합에 기반하여 사용자 정의 코드를 생성하는데 쓸 수 있으며, 또한 특정 타입에 대해 부적절한 코드가 만들어지는 것을 막는 데도 쓸 수 있습니다.

댓글 없음:

댓글 쓰기