【D言語】テンプレートの遅延インスタンス化

D言語erの皆さん、こんにちは。

今回は、テンプレートの遅延インスタンス化について語ります。

時に、テンプレート引数としてテンプレートをインスタンス化したものを渡す時、その場でインスタンス化されてほしくない時があります。 例としては、std.traits.Selectを使う場合が挙げられます。


import std.traits;

template T1(T){
    pragma(msg, "T1");
    alias T T1;
}

template T2(T){
    pragma(msg, "T2");
    alias T T2;
}

pragma(msg, Select!(true, T1!int, T2!long));

void main(){}

このコードの出力は、


T1
T2
int

となります。 全くインスタンス化される必要のないT2がインスタンス化されています。 これを何とかします。


無名テンプレートがあれば、それを使って解決できます。 しかし、実際には無いのでその他の方法で頑張ります。 今回は、文字列mixinを使ったLazyテンプレートを使って、インスタンス化を遅延させます。


template Select(bool cond, alias T, alias F){
    static if(cond) alias T!() Select; else alias F!() Select;
}

template Lazy(string src){
    template Lazy(){
        mixin("alias " ~ src ~ " Lazy;");
    }
}

template T1(T){
    pragma(msg, "T1");
    alias T T1;
}

template T2(T){
    pragma(msg, "T2");
    alias T T2;
}

pragma(msg, Select!(true,  Lazy!q{ T1!int }, Lazy!q{ T2!long }));
pragma(msg, Select!(false, Lazy!q{ T1!int }, Lazy!q{ T2!long }));

void main(){}

このコードの出力は、


T1
int
T2
long

ちゃんとインスタンス化が遅延されています!!


この文字列mixinを使う方法ですが、いくつか問題があります。

  • 文字列mixinを使っているので、文字列内のシンボルがLazyテンプレートから見えなきゃいけない。
  • 文字列mixinを使っているので、コンパイルが少し遅くなる気がする。
  • 遅延インスタンス化されたものを受け取る側も、それを考慮する必要がある。

この方法はあまり汎用的には使えませんが、必要になった時に使ってみてください。