More C++ Idioms/メタ関数(Metafunction)
メタ関数(Metafunction)
[編集]意図
[編集]- 複雑な型計算アルゴリズムをカプセル化する。
- コンパイル時型選択テクニックを用いて型を生成する。
別名
[編集]動機
[編集]テンプレートは C++ の強力な機能であり、コンパイル時に任意の計算を実行することができる。これはテンプレートメタプログラミングとして知られている。コンパイル時に実行される計算の単純な例として (1) コンパイル時定数に基づく型の選択 (2) 階乗の計算 がある。実際のところ、C++ テンプレートはチューリング完全な C++ のサブ言語である。メタ関数(Metafunction)イディオムは C++ でコンパイル時アルゴリズムを記述する基本的な方法である。
利用あるいは再利用しやすいようにアルゴリズムは(コンパイル時に対するものでも実行時に対するものでも)カプセル化するべきである。一般的に、実行時アルゴリズムは、(当然)実行時に呼び出される関数としてカプセル化される。一方メタ関数とは、実行時での関数に対するコンパイル時の類似物である。通常の関数は値やオブジェクトをパラメータとして受け入れ、値やオブジェクトを返す。しかし、メタ関数は型やコンパイル時定数をパラメータとして受け入れ型や定数を返す。
解法とサンプルコード
[編集]メタ関数はその名に反してクラステンプレートである。メタ関数の実装は大抵テンプレートの特殊化に基づいている。例えば、以下の IF メタ関数、すなわち実行時の if 文に対するコンパイル時の同等物を考えてみよう。以下の例では、最初のパラメータの値に依存して、IF メタ関数は int か long を返す。
template <bool, class L, class R>
struct IF
{
typedef R type;
};
template <class L, class R>
struct IF<true, L, R>
{
typedef L type;
};
IF<false, int, long>::type i; // は long i; と等しい。
IF<true, int, long>::type i; // は int i; と等しい。
以下の Factorial メタ関数は別の例であり、どのように再帰的な階乗計算アルゴリズムが C++ テンプレートを用いてカプセル化されるかを示す。このメタ関数は型ではなく整数値を返す。
template <int N>
struct Factorial
{
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
int x = Factorial<4>::value; // == 24
int y = Factorial<0>::value; // == 1
}
メタ関数(Metafunction)と型生成器(Type Generator)
メタ関数(Metafunction)は型生成器(Type Generator)イディオムよりも汎用的なイディオムである。メタ関数(Metafunction)イディオムの意図はコンパイル時計算をカプセル化しようというものである一方、型生成器(Type Generator)は型の指定を単純化しようというものである。コンパイル時計算の結果として型を生成するメタ関数は、より複雑ではあるが、全て型生成器である。しかし、全てのメタ関数が型生成器であるわけではない。例えば、前記 Factorial メタ関数は計算の結果として整数値を生成し型を生成しない。型生成器と異なり、一般的にメタ関数は コンパイル時制御構造(compile-time control structures)か他のメタ関数を用いて実装される。
Boost.MPL のようなライブラリが C++ テンプレートメタプログラミングを単純化するために、メタ関数とコンパイル時データ構造の大規模なコレクションを提供している。
高階メタ関数
メタ関数をパラメータとして受け取って計算中に使用するメタ関数が存在する。概念的には、別の関数へのポインタあるいは関数オブジェクトをパラメータとして受け取る実行時関数と同様である。差はメタ関数がコンパイル時にのみ存在する点だけである。boost::mpl::transform がそのような高階メタ関数の例である。
既知の利用
[編集]関連するイディオム
[編集]References
[編集]A Deeper Look at Metafunctions -- David Abrahams and Aleksey Gurtovoy