dlang模板和模板化类,结构和函数之间的区别

bli*_*n17 6 templates d

我在D中理解模板时遇到一些麻烦.

我理解struct Foo(T) { }类或函数的作用或等价物是什么,但是什么是template Bar(T) { }?它与类,结构或函数模板有何不同,何时使用?

小智 10

当你看到template bar(T),你可以把它想象成一个命名空间 - 有点像结构或类.就像struct Foo(T),内容当然是模板参数的模板,通常只能通过bar!T.memberName.

我说一般,因为有一些特殊的规则.首先,我们有同名的模板.如果template foo(T)一个成员与模板具有完全相同的名称,那么它foo!T是一个同义词foo!T.foo,并且整个命名空间的想法sorta消失了.内部的其他成员foo!T隐藏且无法访问.实际上,当你编写时struct Foo(T) {},编译器将其转换为template Foo(T) { struct Foo {} }.

另一个特殊情况是mixin模板,它们基本上是在实例化时将逐字删除的片段.也就是说,这段代码(注意mixin前面的关键字template):

mixin template Foo() {
    int i;
}

struct Bar {
    mixin Foo!();
}
Run Code Online (Sandbox Code Playgroud)

在功能上等同于此代码:

struct Bar {
    int i;
}
Run Code Online (Sandbox Code Playgroud)

现在,你为什么要用它template?第一个是模板元编程.如果你看一下std.traits或者std.meta,那些模块都充满了模板.不是mixin模板,不是模板化的结构,类或函数,而只是模板.它们对传递给它们的值和类型进行操作,并返回某种值或类型.

像这样使用的模板的一个非常简单的例子是std.meta.Reverse.它需要一个参数列表并将它们反转,看起来像这样:

template Reverse(TList...)
{
    static if (TList.length <= 1)
    {
        alias Reverse = TList;
    }
    else
    {
        alias Reverse =
            AliasSeq!(
                Reverse!(TList[$/2 ..  $ ]),
                Reverse!(TList[ 0  .. $/2]));
    }
}
Run Code Online (Sandbox Code Playgroud)

您想要使用模板的另一种情况是,在某些情况下应该省略模板类型.假设你自己做Nullable(T),而你想Nullable!(Nullable!T)永远做到Nullable!T.如果你刚写了struct Nullable(T) {},你就不会得到这种行为,而你最终会得到双重可空类型.解决方案是使用模板约束:

struct Nullable(T) if (!isNullable!T) {}
Run Code Online (Sandbox Code Playgroud)

以及处理退化情况的模板:

template Nullable(T) if (isNullable!T) {
    alias Nullable = T;
}
Run Code Online (Sandbox Code Playgroud)

我希望这有一些帮助,请问是否有任何不清楚的地方.:)