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以外にも使えるように拡張されてはいるが・・・