代码之家  ›  专栏  ›  技术社区  ›  Eitan

在D2中交换委托/函数和接口

  •  6
  • Eitan  · 技术社区  · 14 年前

    我希望能够定义一个采用接口的函数,但是可以通过提供相同功能的委托或函数来实现。例如,在C++中我可以写一些类似的东西:

    typedef std::function<int (float)> toInt;
    
    void fun(toInt dg) { ... }
    
    struct impl1 {
        int operator()(float x) { ... }
    };
    
    int impl2(float x) { ... }
    

    然后使用以下任一实现调用它:

    fun(impl1());
    fun(&impl2);
    

    我想在d取得类似的成就。我天真的尝试是这样的:

    interface toInt {
        int opCall(float);
    }
    
    void fun(toInt dg) { ... }
    
    int impl2(float x) { ... }
    
    fun(impl2);
    

    编译器在最后一行抱怨它不能隐式地将impl2转换为toInt类型。我可能只是添加了一个重载的乐趣实现,并使转换显式,但我想知道是否有一个更优雅和一般的方式来做这件事,如上面的C++示例。

    3 回复  |  直到 14 年前
        1
  •  5
  •   Chris Nicholson-Sauls    14 年前

    他认为这基本上是正确的,但是下面的小改动也将使它能够与支持opCall的结构/类一起工作。

    import std.conv;
    import std.stdio;
    import std.traits;
    
    void fun ( T ) ( float value, T pred )
    if ( __traits( compiles, pred( value ) ) && is( ReturnType!pred : int ) )
    {
        writefln( "pred( %f ) -> %s", value, pred( value ) );
    }
    
    struct impl1 {
        int opCall ( float f ) {
            return to!int( f );
        }
    }
    
    int impl2 ( float f ) {
        return to!int( f );
    }
    
    void main () {
        impl1 x;
        fun( 1.0, x );
    
        fun( 2.0, &impl2 );
    
        fun( 3.0, ( float f ){ return to!int( f ); } );
    }
        2
  •  3
  •   dsimcha    14 年前

    正如他提到的,模板在大多数情况下是最好的解决方案。(这是std::function正在做的事情。)如果您不能/不想使用模板,请查看标准功能. 您将发现一个名为 toDelegate()

    import std.functional;
    
    struct Impl1 {
        int doConversion(float x) { return cast(int) x; }
    }
    
    int impl2(float x) { return cast(int) x; }
    
    void fun(int delegate(float) dg) {}
    
    void main() {
        Impl1 impl1;
        fun(&impl1.doConversion);
        fun(toDelegate(&impl2));
    }
    

    你也可以写一些与C++类似的东西。 std::function ref out 由于编译器错误而立即返回参数。

    import std.traits;
    
    interface Function(ReturnType, Args...) {
        ReturnType opCall(Args);
    }
    
    class FunctionImpl(C) : Function!(ReturnType!C, ParameterTypeTuple!C)  {
        C callable;
    
        this(C callable) {
            this.callable = callable;
        }
    
        ReturnType!C opCall(ParameterTypeTuple!C args) {
            return callable(args);
        }
    }
    
    /**Convenience function for creating a Function object w/o explicitly 
      specifying types
     */
    FunctionImpl!C functionObject(C)(C callable) {
         return new typeof(return)(callable);
    }
    
    // Test function.
    uint inc(uint num) {
        return num + 1;
    }
    
    // Test it out.
    void main() {
        auto myFun = functionObject(&inc);
        assert(myFun(1) == 2);
    }
    
        3
  •  3
  •   he_the_great    14 年前

    D区分函数和委托,因为委托不仅仅是指向函数的指针。所以没有一种类型能同时适用于这两种类型。有人讨论过在Phobos中添加函数包装器(正如dsimcha所指出的,它是标准功能删除). 你可以使用模板(我没有最新的编译器来检查它是否有效)

    import std.traits;
    import std.conv;
    
    void fun(F)(F dg) if(isSomeFunction!(F) && __traits(compiles, int a = dg(35.6))
    {  }
    
    struct someStruct {
        int operator(float x) { return to!int(x); }
    };
    
    int impl2(float x) { return to!int(x); }
    
    
    void main() {
        someStruct impl1;
        fun(&impl1.operator);
        fun(&impl2);
    }