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 :(得分: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
=========================================================
当传递给模板参数的参数不匹配时,模板将从重载集中删除。如果在找到匹配项之前过载集变空,则会引发错误。
当IsExpression(is(...)
主表达式)不匹配时,结果为false,并且没有符号引入范围。
答案 1 :(得分:3)
如http://dlang.org/template.html的“参数扣减”部分所述,在推断模板参数的类型时:
- 如果参数没有类型专门化,则参数的类型设置为模板参数。
- 如果类型特化取决于类型参数,则该参数的类型设置为 类型参数的相应部分。
- 如果在检查了所有类型参数后,仍然存在未分配类型的任何类型参数,则为它们分配类型 对应于同一位置的模板参数 TemplateArgumentList。
- 如果应用上述规则不会导致每个模板参数只有一种类型,那么这是一个错误。
醇>
与您的案例相对应的示例是:
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;
}