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

时间:2012-04-13 17:50:40

标签: templates d

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

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

2 个答案:

答案 0 :(得分: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,并且没有符号引入范围。

答案 1 :(得分:3)

http://dlang.org/template.html的“参数扣减”部分所述,在推断模板参数的类型时:

  
      
  1. 如果参数没有类型专门化,则参数的类型设置为模板参数。
  2.   
  3. 如果类型特化取决于类型参数,则该参数的类型设置为   类型参数的相应部分。
  4.   
  5. 如果在检查了所有类型参数后,仍然存在未分配类型的任何类型参数,则为它们分配类型   对应于同一位置的模板参数   TemplateArgumentList。
  6.   
  7. 如果应用上述规则不会导致每个模板参数只有一种类型,那么这是一个错误。
  8.   

与您的案例相对应的示例是:

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