为什么这个模板参数约束不起作用?
问题描述:
读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)));
}
我不理解这种行为。一个解释将不胜感激。
答
当型专业化(冒号后的类型)取决于参数标识符,诸如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,并且没有符号引入到作用域中。
答
如在http://dlang.org/template.html的参数推导部分解释,推断类型的模板参数时:
- If there is no type specialization for the parameter, the type of the parameter is set to the template argument.
- If the type specialization is dependent on a type parameter, the type of that parameter is set to be the corresponding part of the type argument.
- If after all the type arguments are examined there are any type parameters left with no type assigned, they are assigned types corresponding to the template argument in the same position in the TemplateArgumentList.
- If applying the above rules does not result in exactly one type for each template parameter, 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;
}
如果你尝试'struct S(T:void *)' – 2012-04-13 18:11:17
我会指出那些断言不会工作(当然,它们不在2.059上),因为你不能比较类型。你需要他们是一个'is'表达式。 – 2012-04-13 18:32:07
@JonathanMDavis无论如何,在第一个例子中执行's.t =&x'不起作用,并且我得到了'错误:不能隐式地将int *类型的表达式(&x)转换为int'。所以我想这是一个DMD错误? – Arlen 2012-04-13 18:40:00