模板主体内部的模板比较变化

Template comparison changes inside template body

我有一个结构 Foo!T 和一个对任意两个 Foo!T 进行操作的函数。 我希望声明这样的函数

void fun(U)(U a, U b) if (is(U : Foo!T, T...)) { }

然而事实证明我可以声明为

void fun(U)(U a, U b) if (is(U : Foo)) { }

仅当我声明它Foo的正文中。

例如:

struct Foo(T) { 
    void fun1(U)(U b) if (is(U : Foo)) { } 
}

void fun2(U)(U a, U b) if (is(U : Foo)) { }

unittest {
    Foo!int f;
    f.fun1(f);
    f.fun2(f);
}

以上调用失败 struct d.Foo(T) is used as a type fun2fun1,不过还好。

为什么约束 is(U : Foo)Foo 的主体内有效,但不是 外部?

Foo体内的比较is(U : Foo)是否等同于Foo体外的is(U : Foo!V, V...)

在模板化类型中,模板的名称指的是模板的特定实例化,除非明确指定了不同的实例化。例如,

struct Foo(T)
{
    pragma(msg, Foo.stringof);
}
pragma(msg, Foo.stringof);

void main()
{
    Foo!int foo1;
    Foo!string foo2;
}

打印

Foo(T)
Foo!int
Foo!string

打印的第一个 pragma 是紧跟在模板之后的,另外两个是 Foo 实例化时生成的。这样一来,当您引用它时(例如,从成员函数返回它时),您不必在结构声明中的所有地方都涂上 Foo!T 。如果类型有多个模板参数而不是只有一个,这将特别有用。但它 确实 意味着如果你想引用通用模板,你要么需要用特定的参数实例化它 - 例如在 Foo 内部使用 Foo!int 来引用 Foo!int 而不管当前实例是什么 - 或者您需要使用点运算符来指示您想要从外部 Foo范围。例如

struct Foo(T)
{
    pragma(msg, Foo.stringof);
    pragma(msg, .Foo.stringof);
}
pragma(msg, Foo.stringof);

void main()
{
    Foo!int foo1;
    Foo!string foo2;
}

打印

Foo(T)
Foo!int
Foo(T)
Foo!string
Foo(T)

因此,在模板化类型中编写诸如模板约束之类的东西时,请注意在 struct Foo(T)class Foo(T) 中使用 Foo 将意味着特定的实例化和 不是模板本身。

此外,如果您要专门测试 U 是否是 Foo 的实例,我建议您使用 std.traits.isInstanceOf - 例如if(isInstanceOf(Foo, U))。可以说,它确实应该是 isInstantiationOf 而不是 isInstanceOf,但无论如何,它以比使用裸露的 is 表达式更惯用的方式完成工作。

更具体地说,像

这样的模板
struct Foo(T) {}

扩展到等价物

template Foo(T)
{
    struct Foo {}
}

原始模板引用自动转发给模板中与模板同名的成员:

Foo!int foo;
// expands to:
Foo!(int).Foo foo;

您可以使用它来制作出于某种原因需要的 "hidden" 模板成员。例如,std.typecons.Tuple 使用了这种技术:它在 Tuple 模板中定义了一些辅助模板和函数,然后定义了 Tuple 结构。但是您可以像使用模板结构一样使用它。