在类方法中使用委托

时间:2014-02-17 14:08:30

标签: d

我在DMD行为中发现了一些我不理解的东西。

我的代码如下所示:

class C1 {
    private static fun(alias f)() {
        ;
    }
    public static void run() {
        auto f = delegate bool(int x) {return true;} ;
        fun!(f)();
        return;
    }
}

编译器写错误:

Error: template instance fun!(f) cannot use local 'f' as parameter to non-global template fun(alias f)()

所以我必须在类中创建一个委托字段以使其成为全局:

class C1 {
    private static fun(alias f)() {
        ;
    }
    private static bool delegate(int) f;
    public static void run() {
        f = delegate bool(int x) {return true;} ;
        fun!(f)();
        return;
    }
}

编译此代码时没有错误。但是我不明白,为什么我们不能在方法中声明委托?

2 个答案:

答案 0 :(得分:2)

更新:这个问题并不像我原先想象的那么简单。这就是我认为真正发生的事情。正如另一位评论者指出的那样,我忘记了别名模板参数允许传入任何类型的符号,甚至是局部变量。在这种情况下,使用函数模板,实例化模板需要指向其上下文(run的主体)的指针,以便它可以访问传入的局部变量(如委托f)别名params。但是,fun已经是类的静态成员,这意味着它已经有一个上下文指针(静态类上下文)。现在,D编译器的一个已知限制是它无法处理需要两个或更多上下文指针的委托。 (这就是为什么它在错误消息中说“非全局” - 全局函数模板起作用,因为它们没有上下文。)

第二个例子有效,因为f不再是局部变量;它是一个静态成员。它在run范围内初始化的事实不会改变它。

请参阅以下问题:

希望对编译器有更多内幕知识的人可以确认此诊断。

原始回答

(我的原始答案解释了这个错误,说模板参数需要是不可变的,并且在编译时是已知的,也不是代理(简称函数)。这只是半对... alias params don在编译时需要知道值。但是,关于它的部分需要是常规函数而不是委托是正确的。)

我原来的答案中的这些变通方法仍然适用:

以其中一种方式声明f将确保它可以作为模板参数传递:

// Not a delegate, not a local variable anymore (enum)
enum f = function bool(int x) {return true;};

// "static" == not delegate
static bool f(int x) { return true; }
fun!(f)();

// Or pass it as a literal (inferred to be non-delegate)
fun!((int x) => true);

常规方法可以作为模板参数传递:

class C2 {
    private static fun(alias f)() {
        assert(f(1) == true);
    }
    private static bool g(int) { 
        return true; 
    }
    public static void run() {
        fun!(g)();
    }
}

或者将其作为常规参数传递,而不是模板参数:

class C1 {
    private static fun(bool delegate(int) f) {
        assert(f(1) == true);
    }
    public static void run() {
        auto f = delegate bool(int x) { return true; };
        fun(f);
    }
}

答案 1 :(得分:1)

我没有答案,但这里有一些不适合评论的想法。

  

错误:模板实例很有趣!(f)不能使用本地'f'作为参数   到非全局模板 fun(别名f)()

您会注意到实际上有两种方法可以解决此问题。将'f'转换为非局部变量,就像你做的那样。或者将模板设为全局。

这表明将本地模板实例化为局部变量存在一些困难。我猜这意味着它是技术/实施挑战而不是实际限制(即不要这样做因为......)。

更新:J.米勒没有意识到,别名参数绑定到符号而不是值。在你的情况下,符号f在编译时是已知的,因此这段代码可以工作:

class C1 {
    public static void run() {
        auto f = delegate bool(int x) {return true;} ;
        fun!(f)();
        return;
    }
}

private void fun(alias f)() {
    import std.stdio;
    writeln(f(3));
}

void main () {
    new C1;
    C1.run();
}