为什么这个模板参数约束不起作用?

4

阅读 templates-revisited

struct S(T : T*) {
  T t;  // t is supposed to be of type 'int*', but it's of type 'int', why?
}

void main() {

  int x = 123;
  S!(int*) s;
  static assert(is(typeof(s.t) == typeof(&x)));
}

上述代码无法编译。

奇怪的是,下面的代码可以成功编译:

struct S(T : int*) {
  T t;
}

void main() {

  int x = 123;
  S!(int*) s;
  static assert(is(typeof(s.t) == typeof(&x)));
}

我不理解这种行为。希望能够给出解释。


如果你尝试使用 struct S(T:void*) - ratchet freak
我要指出这些断言不起作用(肯定地说,在2.059上它们不起作用),因为您无法比较类型。 您需要将它们放在“is”表达式中。 - Jonathan M Davis
@JonathanMDavis 无论如何,在第一个示例中执行s.t =&x是不起作用的,我会得到“错误:无法将类型为int *的表达式(&x)隐式转换为int”。所以我猜这是DMD的一个bug? - Arlen
@Arlen 我并不是在质疑这个问题本身。你的意思已经很清楚了,如果使用正确的 is 表达式,确实存在这个问题。我只是指出这些断言本身是不正确的。 - Jonathan M Davis
2个回答

5

当类型特化(冒号后面的类型)依赖于参数标识符时,比如 T : T*,如果有匹配,结果标识符指的是标识符(T)在类型特化中(推断类型)的作用。

否则,如果特化是独立的,比如 T : int*,结果标识符是类型特化的别名。

例子:

=========================================================
Argument T        | Specialization     | Result
=========================================================
void              | T : void           | void
char              | T : void           | <no match>
int*              | T : T*             | int
immutable(char)[] | T : T[]            | immutable(char)
immutable(char)[] | T : immutable(T)[] | char
=========================================================

当模板参数传递的参数不匹配时,该模板将从重载集中删除。如果重载集在找到匹配项之前变为空,则会引发错误。

IsExpressionis(...)主表达式)出现不匹配时,结果为false,并且不会引入任何符号进入作用域。


3
http://dlang.org/template.html中的“Argument Deduction”部分所解释的那样,在推断模板参数类型时:
  1. 如果没有参数的类型专门化,参数的类型设置为模板参数。
  2. 如果类型专门化依赖于类型参数,则该参数的类型设置为类型参数对应的类型参数。
  3. 如果在检查所有类型参数后仍有任何未分配类型的类型参数,则将它们分配给相同位置的模板参数的模板参数列表中的模板参数。
  4. 如果应用上述规则不能为每个模板参数恰好产生一个类型,则出错。

而与您的情况相对应的示例是:

template TBar(T : T*) { }
alias TBar!(char*) Foo3;   // (2) T is deduced to be char

因此,在您的第一个示例中看到的行为是预期的。因为T在两侧,T最终被评估为模板参数将导致T*。因此,由于模板参数是int*T*将是int*,并且T最终变成int。您所拥有的非常类似于std.traits.pointerTarget

/**
Returns the target type of a pointer.
*/
template pointerTarget(T : T*)
{
    alias T pointerTarget;
}

你的第二个示例可以编译,因为该模板要求T可以隐式转换为int*。而且,由于int*可以隐式转换为自身,当你将int*作为模板参数传递时,它就起作用了。导致问题的原因是当T在两侧时,右侧表达式依赖于左侧。
现在,我假设您实际上想要测试的是模板参数是否为指针?如果是这种情况,那么您应该使用std.traits.isPointer
struct S(T)
    if(isPointer!T)
{
    T t;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接