【问题标题】:delegate is deduced to void when calling template function in D(LDC2)在 D(LDC2) 中调用模板函数时,委托被推断为 void
【发布时间】:2018-09-10 22:20:43
【问题描述】:

我有一个使用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);

【问题讨论】:

    标签: templates d type-inference


    【解决方案1】:

    如果在委托中没有给出类型名称,它会将其作为模板(在错误消息中键入 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 之后完成的。

    但是如果没有模板函数的话....我不知道,我认为解决方案是做两层,所以显式类型被命名为一个或另一个,但我只是还没想到还没有解决(因为我现在还有其他事情要做)。

    【讨论】:

    • 两层方法效果很好。感谢分享:)
    猜你喜欢
    • 1970-01-01
    • 2015-03-18
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 2020-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多