2012-04-13 90 views
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))); 
} 

我不理解这种行为。一个解释将不胜感激。

+0

如果你尝试'struct S(T:void *)' – 2012-04-13 18:11:17

+0

我会指出那些断言不会工作(当然,它们不在2.059上),因为你不能比较类型。你需要他们是一个'is'表达式。 – 2012-04-13 18:32:07

+0

@JonathanMDavis无论如何,在第一个例子中执行's.t =&x'不起作用,并且我得到了'错误:不能隐式地将int *类型的表达式(&x)转换为int'。所以我想这是一个DMD错误? – Arlen 2012-04-13 18:40:00

回答

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的参数推导部分解释,推断类型的模板参数时:

  1. If there is no type spe­cial­iza­tion for the pa­ra­me­ter, the type of the pa­ra­me­ter is set to the tem­plate ar­gu­ment.
  2. If the type spe­cial­iza­tion is de­pen­dent on a type pa­ra­me­ter, the type of that pa­ra­me­ter is set to be the cor­re­spond­ing part of the type ar­gu­ment.
  3. If after all the type ar­gu­ments are ex­am­ined there are any type pa­ra­me­ters left with no type as­signed, they are as­signed types cor­re­spond­ing to the tem­plate ar­gu­ment in the same po­si­tion in the Tem­plateAr­gu­mentList.
  4. If ap­ply­ing the above rules does not re­sult in ex­actly one type for each tem­plate pa­ra­me­ter, then it is an error.

和对应于你的情况的例子是:

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