我有一个结构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
fun2
。但是,fun1
没问题。
为什么约束is(U : Foo)
在Foo
的正文内有效,但不是
外?
is(U : Foo)
正文体内的比较Foo
是is(U :
Foo!V, V...)
的正文之外的Foo
吗?
答案 0 :(得分:1)
在模板化类型中,模板的名称是指模板的特定实例化,除非它明确地给出了不同的实例化。例如,
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是模板后面的pragma,另一个是Foo
实例化时生成的。这样就可以在你引用它时(例如从成员函数返回它时)不必在结构声明中的所有位置涂抹Foo!T
。如果类型具有多个模板参数而不是一个模板参数,则此功能特别有用。但它确实意味着如果你想引用通用模板,你需要用特定的参数来实例化它 - 例如使用Foo!int
内的Foo
来引用Foo!int
,无论当前的实例是什么 - 或者您需要使用点运算符来指示您希望Foo
来自外部范围。 e.g。
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)
因此,当在模板化类型中编写模板约束之类的内容时,请注意在Foo
或struct Foo(T)
内使用class Foo(T)
将意味着特定的实例化而不是< / em>模板本身。
此外,如果您正在专门测试U
是否为Foo
的即时消息,我建议使用std.traits.isInstanceOf
- 例如if(isInstanceOf(Foo, U))
。可以说,它确实应该是isInstantiationOf
而不是isInstanceOf
,但无论如何,它使用的方式比使用裸is
表达式更为惯用。
答案 1 :(得分:1)
更具体地说,像
这样的模板struct Foo(T) {}
扩展为等效的
template Foo(T)
{
struct Foo {}
}
原始模板引用自动转发到模板中与模板名称相同的成员:
Foo!int foo;
// expands to:
Foo!(int).Foo foo;
您可以使用它来制作您出于某种原因所需的“隐藏”模板成员。 std.typecons.Tuple
使用这种技术,例如:它在Tuple
模板中定义了许多辅助模板和函数,然后定义了Tuple
结构。但你可以使用它,好像它只是一个模板化的结构。