在 D(LDC2) 中调用模板函数时,委托被推导为无效
delegate is deduced to void when calling template function in D(LDC2)
我有一个使用 Algebraic
.
编写的自定义 Option
类型
struct None{};
struct Some(T){
T t;
alias t this;
T get(){
return t;
}
};
alias Option(T) = Algebraic!(Some!(T), None);
Option!T some(T)(T t){
return Option!T(Some!T(t));
}
Option!T none(T)(){
return Option!T(None());
}
然后我尝试写一些基本的便利函数:
T getValue(T,uint size)(VariantN!(size, Some!T, None) opt){
return opt.get!(Some!T).t;
}
bool isDefined(T, uint size)(VariantN!(size, Some!T, None) opt){
return opt.convertsTo!(Some!T);
}
A match(A,T,uint size)(VariantN!(size, Some!T, None) opt, A delegate(T) some, A delegate() none){
if(opt.isDefined!(T,size)){
return some(opt.getValue!(T,size));
}else{
return none();
}
}
当调用 match
编译器无法推断出模板的正确参数时:
Option!int test = some(1);
bool boolReturn = test.match((x) => false, () => true);
错误:
Error: template util.match cannot deduce function from argument types !()(VariantN!(4LU, Some!int, None), void, bool function() pure nothrow @nogc @safe), candidates are:
src/util.d(79,3): util.match(A, T, uint size)(VariantN!(size, Some!T, None) opt, A delegate(T) some, A delegate() none)
错误输出表明 match
的第二个参数(意思是 bool delegate(int)
或 (x) => false
)被推断为 void
。为什么?
此示例编译(完全相同,但明确给出了 x 的类型):
Option!int test = some(1);
bool boolReturn = test.match((int x) => false, () => true);
如果委托中没有给出类型名称,它会将其作为模板(在错误消息中键入 void),在实例化时将具有推断的类型......在这里它想被推断为类型T,本身就是根据参数推断出的参数。
问题是编译器试图推断 (x) => 模板,同时推断函数调用,但不知道先做哪一个,所以它不能深入足够。如果你在任何一个地方明确提到它,它就会打破循环:
//有效
bool boolReturn = test.match!(bool, int)((x) => false, () => true);
或
//有效
test.match((int x) => false)
但我不确定如何自动执行...我尝试用不同的安排将它们解耦,但还没有成功....
Phobos 通常解决这个问题的方法是将委托作为 alias
模板参数而不是运行时参数。将签名更改为:
typeof(none()) match(alias some, alias none, T, uint size)(VariantN!(size, Some!T, None) opt) {
并将调用更改为:
bool boolReturn = test.match!((x) => false, () => true);
之所以能够编译,是因为您将推理移到了两层:首先,编译器接受那些仍处于模板形式的委托作为参数。然后它接受 test
并计算出它的类型来推断其他参数。然后它进入正文并实际看到 调用 到 some
,并在正文中实例化它的参数类型。之所以有效,是因为推断类型是在主体外部的签名层已知类型 T 之后完成的。
但是如果不使用模板函数...我不知道,我认为解决方案是做两层,以便显式类型在一个或另一个中命名,但我只是没有'我还没有想出来(而且 tbh 可能会停止尝试,因为我现在还有其他事情要做)。
我有一个使用 Algebraic
.
Option
类型
struct None{};
struct Some(T){
T t;
alias t this;
T get(){
return t;
}
};
alias Option(T) = Algebraic!(Some!(T), None);
Option!T some(T)(T t){
return Option!T(Some!T(t));
}
Option!T none(T)(){
return Option!T(None());
}
然后我尝试写一些基本的便利函数:
T getValue(T,uint size)(VariantN!(size, Some!T, None) opt){
return opt.get!(Some!T).t;
}
bool isDefined(T, uint size)(VariantN!(size, Some!T, None) opt){
return opt.convertsTo!(Some!T);
}
A match(A,T,uint size)(VariantN!(size, Some!T, None) opt, A delegate(T) some, A delegate() none){
if(opt.isDefined!(T,size)){
return some(opt.getValue!(T,size));
}else{
return none();
}
}
当调用 match
编译器无法推断出模板的正确参数时:
Option!int test = some(1);
bool boolReturn = test.match((x) => false, () => true);
错误:
Error: template util.match cannot deduce function from argument types !()(VariantN!(4LU, Some!int, None), void, bool function() pure nothrow @nogc @safe), candidates are:
src/util.d(79,3): util.match(A, T, uint size)(VariantN!(size, Some!T, None) opt, A delegate(T) some, A delegate() none)
错误输出表明 match
的第二个参数(意思是 bool delegate(int)
或 (x) => false
)被推断为 void
。为什么?
此示例编译(完全相同,但明确给出了 x 的类型):
Option!int test = some(1);
bool boolReturn = test.match((int x) => false, () => true);
如果委托中没有给出类型名称,它会将其作为模板(在错误消息中键入 void),在实例化时将具有推断的类型......在这里它想被推断为类型T,本身就是根据参数推断出的参数。
问题是编译器试图推断 (x) => 模板,同时推断函数调用,但不知道先做哪一个,所以它不能深入足够。如果你在任何一个地方明确提到它,它就会打破循环:
//有效 bool boolReturn = test.match!(bool, int)((x) => false, () => true);
或
//有效 test.match((int x) => false)
但我不确定如何自动执行...我尝试用不同的安排将它们解耦,但还没有成功....
Phobos 通常解决这个问题的方法是将委托作为 alias
模板参数而不是运行时参数。将签名更改为:
typeof(none()) match(alias some, alias none, T, uint size)(VariantN!(size, Some!T, None) opt) {
并将调用更改为:
bool boolReturn = test.match!((x) => false, () => true);
之所以能够编译,是因为您将推理移到了两层:首先,编译器接受那些仍处于模板形式的委托作为参数。然后它接受 test
并计算出它的类型来推断其他参数。然后它进入正文并实际看到 调用 到 some
,并在正文中实例化它的参数类型。之所以有效,是因为推断类型是在主体外部的签名层已知类型 T 之后完成的。
但是如果不使用模板函数...我不知道,我认为解决方案是做两层,以便显式类型在一个或另一个中命名,但我只是没有'我还没有想出来(而且 tbh 可能会停止尝试,因为我现在还有其他事情要做)。