logo MSJO.kr

Template MetaProgramming(TMP)

2021-03-26
MsJ
   

템플릿 메타프로그래밍(template metaprogramming)은 템플릿을 사용하는 프로그래밍 기법으로, 컴파일러에게 프로그램 코드를 생성하도록 하는 방식이다. 이러한 기법은 컴파일 시점에 많은 것을 결정하도록 하여, 실행 시점의 계산을 줄여준다. 이 기법은 C++ 프로그래밍 언어에서 주로 사용된다1.

TMP는 버그를 찾기 쉽지도 않고 구현도 어렵지만, 사용하는 이유는 많은 C++ 라이브러리들이 TMP 를 이용해서 구현되었고, TMP 를 통해서 컴파일 타임에 여러 오류들을 잡아낼 수도 있으며 속도가 매우 중요한 프로그램의 경우 TMP 를 통해서 런타임 속도도 향상2 시킬 수 있기 때문이다.

TMP에 대한 살펴볼 만한 실제 사례는 C++Builder의 template 버그 문제로 볼랜드포럼의 글 <아래 컴파일 에러는 엠바에서 템플릿코드를 엉터리로 구현해 놨기 때문>3에서 볼 수 있다.

아래의 예제는 콜라츠 추측(Collatz)을 C#과 C++ 언어로 각각 구현한 예제4를 보여주고 TMP를 사용한 C++의 소스가 컴파일 타임에서 C#과 어떠한 차이가 있는지 보여준다.

CS 예제
using System.Linq;
using System.Collections.Generic;

namespace CollatzCS
{
    class Program
    {
        public static IEnumerable<(uint count, uint value)> Collatz(uint seed)
        {
            uint count = 1;
            yield return (count, seed);

            while (seed > 1)
            {
                if (seed % 2 == 0)
                    seed /= 2;
                else
                    seed = 3 * seed + 1;

                yield return (++count, seed);
            }
        }

        static void Main(string[] args)
        {
            // Collatz : 런타임에 실행
            var col = Collatz(100);
            foreach (var val in col)
            {
                System.Console.WriteLine($"{val.count}: {val.value}");
            }
            System.Console.WriteLine("------------------------");
            System.Console.WriteLine($"Collatz of 100 = {col.Count()}");
        }
    }
}

CPP 예제
#include <iostream>

using namespace std;

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

template <>
struct Factorial<1>
{
    static const unsigned value = 1;
};

template <unsigned depth, unsigned seed, bool odd>
struct CollatzBase
{
};

template <unsigned depth, unsigned seed>
struct CollatzBase<depth, seed, true> : public CollatzBase<depth + 1, seed * 3 + 1, (seed * 3 + 1) % 2>
{
};

template <unsigned depth, unsigned seed>
struct CollatzBase<depth, seed, false> : public CollatzBase<depth + 1, seed / 2, (seed / 2) % 2>
{
};

template <unsigned depth>
struct CollatzBase<depth, 1, true> // false <-> true
{
    static const unsigned count = depth;
};

template <unsigned seed>
struct Collatz : public CollatzBase<1, seed, seed % 2>
{
};

int main(void)
{
    // Factorial 예제
    constexpr unsigned fact5 = Factorial<5>::value;
    cout << "Factorial 5 = " << fact5 << endl;
    cout << "Factorial 10 = " << Factorial<10>::value << endl;
    cout << "-------------------------------" << endl;

    // Collatz : 컴파일 타임에 실행
    cout << "Collatz of 100 = " << Collatz<100>::count << endl;
}
Reference
  1. 위키백과, “템플릿 메타프로그래밍”
  2. 모두의 코드, “TMP를 왜 쓰는가?”
  3. 볼랜드포럼, “아래 컴파일 에러는 엠바에서 템플릿코드를 엉터리로 구현해 놨기 때문”
  4. Coding Tutorials, “C++ Template Metaprogramming”

Prεv(Θld)   Nεxt(Nεw)
Content
Search     RSS Feed     BY-NC-ND