kubo39's blog

ただの雑記です。

isInstanceOfテンプレートとalias templates

Slackで以下のコードが通らないのはなぜ?という話があった。

import std;

static assert(isInstanceOf!(Array, Array!char));  // OK!
static assert(isInstanceOf!(Regex, Regex!char));  // Compile Error!

どうもこれを調べてみると、alias templatesの場合だとうまくいかないらしい。

public alias Regex(Char) = std.regex.internal.ir.Regex!(Char);

isInstanceOfは内部的にis式を用いているので、こういったことになっている。

struct S1(Char) {}
alias S2(Char) = S1!Char;

static if (is(S1!char == T3!Args3, alias T3, Args3...))
{
    static assert(__traits(isSame, T3, S1));
    pragma(msg, T3);  // S1(Char)
    static assert(__traits(isTemplate, S1));
    static assert(__traits(isTemplate, T3));
    pragma(msg, __traits(identifier, T3));  // S1
    pragma(msg, T3!char);  // S1!char
    static assert(is(T3!char == S1!char));
    static assert(is(Args3[0] == char));
}

static if (is(S2!char == T4!Args4, alias T4, Args4...))
{
    static assert(!__traits(isSame, T4, S2));
    pragma(msg, T4);  // S1(Char)
    static assert(__traits(isTemplate, S2));
    static assert(__traits(isTemplate, T4));
    pragma(msg, __traits(identifier, T4));  // S1: コピペミスではなく、alias templatesの別名参照先の方を指している
    pragma(msg, T4!char);  // S1!char
    static assert(is(T4!char == S2!char));
    static assert(is(Args4[0] == char));
}

現状の言語機能では型のaliasを取るtraitsはあるが、templateのaliasを取る方法は提供されていない。 また、これは言語機能として提供しないと(自分が知る限りでは)取得することはできない。

最初に戻ると、isInstanceOfの実装としてaliasを考慮しないようになっているのはどうなんだ?という気もしてくる。