TMP

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

TMP

投稿記事 by beatle » 13年前

Template Meta Programming
C++の強力なテンプレートを使ってプログラミングしよう
チャットでちょっと話題になりましたので,記事にしてみました.

普通テンプレートといえば,コンテナの要素型を抽象化するために使います.STLのstd::vector,std::listなんかはいい例ですね.

CODE:

std::vector int_vector;
std::vector string_vector;
しかし,このテンプレートをもっと特殊な用途に使うことを思いついちゃった人がいました.それが「テンプレートメタプログラミング(TMP)」です.
TMPではメタ関数を定義してプログラミングします.

int_double_switchは,引数の真偽に応じて,intかdoubleを返す簡単なメタ関数です.

CODE:

template 
struct int_double_switch
{
    typedef int type;
};

template 
struct int_double_switch
{
    typedef double type;
};
C++的にはint_double_switchは単なる構造体なのですが,TMP的にはメタ関数と呼びます.なんで関数なのかは,int_double_switchの使い方を見れば一目瞭然です.

CODE:

int main()
{
    int_double_switch::type a = 1.2;
    int_double_switch::type b = 1.2;

    std::cout = 0)
     = |x| (x 
struct remove_pointer
{
    typedef T type;
};

template 
struct remove_pointer
{
    typedef typename remove_pointer::type type;
};
使い方は次にようになります.

CODE:

remove_pointer::type a = 2;
remove_pointer::type b = 3;
remove_pointerメタ関数は,引数Tがポインタ型だったら,そのポインタをすべて除去した型を::typeで返します.
remove_pointerもやはりテンプレートの特殊化を使って定義していますね.int_double_switchと違い,こちらは再帰関数になっています.

次は,引数が浮動小数点数型かそうでないかを見分けるメタ関数is_floating_pointです.

CODE:

template 
struct is_floating_point
{
    static const bool value = false;
};

template 
struct is_floating_point
{
    static const bool value = true;
};

template 
struct is_floating_point
{
    static const bool value = true;
};

template 
struct is_floating_point
{
    static const bool value = true;
};

int main()
{
    std::cout ::value ::value ::value という型のメタ関数を定義します.enable_ifは,引数valueがtrueのときtypeとしてTを返し,引数valueがfalseのとき何も返さないメタ関数です.
[code=Cpp]
template 
struct enable_if
{
    typedef T type;
};

template 
struct enable_if
{
};
そして,enable_ifとis_floating_pointを用いると,引数が浮動小数点数かそうでないかによって,関数定義を変えることができます.

CODE:

template 
typename enable_if::value>::type
f(T value)
{
    std::cout 
typename enable_if::value>::type
f(T value)
{
    std::cout ::value>::type」という長ったらしい記述で表されていることが分かるかどうかがポイント.
enable_ifの定義を見ると,enable_ifの引数がfalseのとき,enable_ifは空っぽですから,enable_if::typeはコンパイルエラーに(普通は)なります.
ですから,f(1);と書くと
enable_if::value>::type
→enable_if::type
→エラー!
となりそうです.しかし,テンプレートの置き換えに失敗してもエラーじゃない,というルール「SFINAE」のお陰で,これはエラーにならず,単に「元からそんな定義なんてなかった」ことになります.
下側のfの定義はTがintのときにバッチリ有効になりますから,fの定義がかぶることなく,引数が浮動小数点数かどうかによってfの定義を切り替えることに成功しました.
最後に編集したユーザー beatle on 2012年2月11日(土) 08:32 [ 編集 1 回目 ]

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前

Re: TMP

投稿記事 by MoNoQLoREATOR » 13年前

理論はわかったのですが、それが活用できる場面が思いつきません。
どういったケースにおいて便利なのですか?

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: TMP

投稿記事 by beatle » 13年前

例えばですね,次元数の分からないvector...>>の型を持つ多次元配列の,すべての要素の和を求めるプログラムを手動で書くのは難しいですが,TMPで書くことができます.
ちなみに,Hogeにはintとかdoubleとか,はたまた自作クラスとか,+演算子で加算できるすべての型が入ります.