4

重新阅读模板:

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)));
}

我不明白这种行为。解释将不胜感激。

4

2 回答 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,并且不会将符号引入范围。

于 2012-04-13T19:20:32.233 回答
3

如http://dlang.org/template.html的参数推导部分所述,推导模板参数的类型时:

  1. 如果参数没有类型特化,则参数的类型设置为模板实参。
  2. 如果类型特化依赖于类型参数,则该参数的类型设置为类型参数的对应部分。
  3. 如果在检查了所有类型参数之后,还有任何类型参数没有分配类型,则为它们分配与 TemplateArgumentList 中相同位置的模板参数相对应的类型。
  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*作为模板参数传递时,它可以工作。给你带来麻烦的是when Tis on both,因为表达式的右边依赖于左边。

现在,我假设您实际上打算在这里测试的是模板参数是一个指针?如果是这种情况,那么您应该使用std.traits.isPointer

struct S(T)
    if(isPointer!T)
{
    T t;
}
于 2012-04-13T18:43:46.323 回答