模板比较在模板体内更改

时间:2016-03-25 14:55:40

标签: templates metaprogramming d

我有一个结构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)正文体内的比较Foois(U : Foo!V, V...)的正文之外的Foo吗?

2 个答案:

答案 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)

因此,当在模板化类型中编写模板约束之类的内容时,请注意在Foostruct 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结构。但你可以使用它,好像它只是一个模板化的结构。