【D言語】任意のメンバー関数の存在を確かめる方法
前回の記事では”型Tがメンバ関数fooを持っているかどうかを確かめるテンプレート”を紹介しました。 しかし、fooで決め打ちというのは、使い勝手があまり良くありません。 そんなわけで、今回の記事では”型Tが任意のメンバ関数を持っているかどうかを確かめるテンプレート”を紹介します。
前回のテンプレートの引数に、”調べる関数の名前”を追加します。 今回の場合、こっちのほうが簡単という理由で__traits(hasMember, …)を使っていきます。
import std.stdio, std.traits;
template hasFunction(T, string name){
static if(__traits(hasMember, T, name)){
enum hasFunction = mixin("isSomeFunction!(T." ~ name ~ ")");
}else{
enum hasFunction = false;
}
}
struct Hoge{
void hoge(){}
string piyo(int i){ return ""; }
double fuga;
}
void main(){
hasFunction!(Hoge, "hoge").writeln(); // true
hasFunction!(Hoge, "piyo").writeln(); // true
hasFunction!(Hoge, "fuga").writeln(); // false
hasFunction!(Hoge, "hogehoge").writeln(); // false
}
上のコードでは、hasFunctionは型Tがnameという名前のメンバを持っているかを調べた後、そのメンバが関数かどうかも調べています。 関数かどうか調べるときに、std.traits.isSomeFunctionを使っていますが、このテンプレートの引数は文字列ではなく、調べたいもの自体です。 つまり、isSomeFunctionは
isSomeFunction!(T.hoge)
や
isSomeFunction!(T.piyo)
という風にしか使えないという事です。 当然、hasFunctionはメンバを文字列で受け取っているため、上のように書けません。 そこで、伝家の宝刀であるmixinを使っています。
mixin("isSomeFunction!(T." ~ name ~ ")")
mixinは、コンパイル時に評価できる文字列(つまりテンプレート引数の文字列や、それの連結など)を、D言語のソースコードとして埋め込むことが出来るD言語の機能です。 上のコードでは、mixinを使い、isSomeFunction!(T.hoge)やisSomeFunction!(T.piyo)という風にisSomeFunctionを使うことを可能にしています。
まとめ
見ての通り、D言語は、コンパイル時にテンプレートやmixinを使って色々と出来る言語です。 テンプレートで実現が難しいことでも、D言語だとmixinを使えば大抵実現できます。 コンパイル時処理に興味が出てきた方は、D言語を使ってみると楽しいかもしれません。