D言語でテンプレートメタプログラミング(2)

前回の続き。


C++っぽくenable_ifを実装してみようと思ったが、改めてD言語仕様を見るに、どうやらD言語の作法ではStaticIf条件とIs()式を使えということらしい。

class hogehoge(T){
  static if(is(T == int)){
    // Tがintである時の実装・・・
  }
  else{
    // そうでない時の実装・・・
  }
}

コンパイル時に静的に決まるTの型によってhogehoge!(T)の実装が切り替えられる。


なお、boost/utility/enable_ifを何も考えずにD言語に焼きなおしたコードは

// enable_if本体*1
struct enable_if(bit T){
  alias void type;
}
struct enable_if(bit T : false){
}



struct test(T, U : enable_if!(is_same!(T, int)).type){
  const bit flag = true; // Tがintである時の実装?
}
struct test(T, U = void){
  const bit flag = false; // そうでない時の実装?
}

のようになる(と思う)が、いざ試してみるとコンパイルは通るものの、期待した動きはしてくれない。

test!(int).flag #=> false // trueになってほしい
test!(short).flag #=> false

推測の話になってしまうけれど、おそらくテンプレートの特殊化を試行する時の順序がC++とは違うと思われる。(自分がポカミスをしてなければ、だが)
コンパイラの実装が(比較的)簡単」というのが売りの一つだし、そういうのはあえて無視してるのかもしれない。


StaticIfとIsを単純に使ってみた。

is_convertible!(T, U).value // TはUに暗黙の変換が可能?
is_typedef!(T).value // Tはtypedefで新たに定義された型?
is_struct!(T).value // Tは構造体?
is_union!(T).value // Tは共用体?
is_class!(T).value // Tはクラス?
is_interface!(T).value // Tはインターフェース?
is_enum!(T).value // Tは列挙型?
is_function!(T).value // Tは関数ポインタ?
is_delegate!(T).value // Tはデリゲート?

どれもstatic if(is_xxx!(TYPE).value){ ・・・ }のように使用できる。


以下、メモ。

メモその1:
iftype(ほにゃらら){ ・・・ }とstatic if(is(ほにゃらら)){ ・・・ }は等価なのか、と思って試したらどうもiftypeはobsoleteらしい。そうならそうと仕様書(この部分)に堂々と残しておかなければいいのに。
メモその2:
typeid(ほにゃらら)はTypeInfoクラスのインスタンスを返すらしいがそのTypeInfoの使い方が見当たらんぞ。と思ったらForumのログ(英語)にごろごろと見つかる。読むのめんどいがヒマな時にでもぼちぼち読むか。とりあえずtypeid(なんかの型やインスタンス).toString()で型名を指すchar[]が返されることは分かった。


*1:激しく適当に思えるが、実際のenable_ifも概ねこんなものである。void以外にも使えるように拡張されてはいるが・・・