C++の強力なテンプレートを使ってプログラミングしよう
チャットでちょっと話題になりましたので,記事にしてみました.
普通テンプレートといえば,コンテナの要素型を抽象化するために使います.STLのstd::vector,std::listなんかはいい例ですね. しかし,このテンプレートをもっと特殊な用途に使うことを思いついちゃった人がいました.それが「テンプレートメタプログラミング(TMP)」です.
TMPではメタ関数を定義してプログラミングします.
int_double_switchは,引数の真偽に応じて,intかdoubleを返す簡単なメタ関数です.
template
struct int_double_switch
{
typedef int type;
};
template
struct int_double_switch
{
typedef double type;
};
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;
};
remove_pointerもやはりテンプレートの特殊化を使って定義していますね.int_double_switchと違い,こちらは再帰関数になっています.
次は,引数が浮動小数点数型かそうでないかを見分けるメタ関数is_floating_pointです.
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
{
};
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の定義を切り替えることに成功しました.