【问题标题】:Template comparison changes inside template body模板体内的模板比较变化
【发布时间】:2016-03-25 14:55:39
【问题描述】:

我有一个结构 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 的主体内有效,但不是 外部?

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

【问题讨论】:

  • 这有点像虫子的味道,但它也可能是一个奇怪的同名事物...... Foo!T 内部的 Foo 正在扩展为 Foo!T(尝试在内部使用 pragma(msg, Foo)。在外部, 没有实例化。所以它们不一样:在 Foo!int 内部,它会接受其他 Foo!int,但你的 fun2 也会接受 Foo!string 和其他。

标签: templates metaprogramming d


【解决方案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是模板之后的那个,另外两个是在Foo被实例化时生成的。这样一来,当您引用它时(例如,从成员函数返回它时),您不必在 struct 声明内的所有地方都涂抹 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 表达式更惯用的方式完成这项工作。

【讨论】:

  • 规范中的定义在哪里?我认为这是真的,但无法证明它是否有意。
  • 我快速浏览了一下规范,但没有看到。所以,我的猜测是它实际上并没有正式记录。多年来一直都是这样,而且规范经常缺少这样的细节。 :|
【解决方案2】:

更具体地说,像这样的模板

struct Foo(T) {}

扩展为等价物

template Foo(T)
{
    struct Foo {}
}

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

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

您可以使用它来制作出于某种原因需要的“隐藏”模板成员。 std.typecons.Tuple 使用了这种技术,例如:它在 Tuple 模板中定义了许多帮助模板和函数,然后定义了 Tuple 结构。但是您可以将它当作一个模板结构来使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-05
    • 2023-03-29
    相关资源
    最近更新 更多