在D2中交换委托/功能和接口

时间:2010-09-07 23:31:49

标签: interface delegates d

我希望能够定义一个接受接口的函数,但可以使用提供相同功能的委托或函数来实现。例如,在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);

(这个float-&gt; int转换只是一个简单的例子来说明原理,而不是我的实际功能。)

我想在D中实现类似的东西。我天真的尝试是这样的:

interface toInt {
    int opCall(float);
}

void fun(toInt dg) { ... }

int impl2(float x) { ... }

fun(impl2);

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

3 个答案:

答案 0 :(得分:5)

he_the_great基本上是正确的,但是下面的小改动也会使它与支持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 ); } );
}

答案 1 :(得分:3)

D区分函数和委托,因为委托大于指向函数的指针。所以没有类型可以兼顾两者。已经讨论过将函数的包装器添加到Phobos中(如dsimcha指出的那样,它是std.functional.toDelegate)。您可以使用模板(我无权访问最新的编译器来检查它是否有效)

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);
}

答案 2 :(得分:3)

正如he_the_great所提到的,模板是大多数情况下的最佳解决方案。 (无论如何,这都是std :: function。)如果你不能/不想使用模板,请查看std.functional。你会发现一个名为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相当的东西,这可能是微不足道的。事实上,我会在这里做。请注意,虽然这不能正确处理refout参数或由于编译器错误而立即返回。

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);
}