Delegate / Feature and Interface Exchange in D2

I would like to be able to define a function that accepts an interface, but can be executed using a delegate or functions that provide the same functionality. For example, in C ++, I can write something like:

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

And then call it using any implementation:

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

(This conversion float-> int is just a simplified example illustrating the principle, not my actual functionality).

I would like to achieve something similar in D. My naive attempt was this:

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

The compiler complains about this last line that it cannot implicitly convert impl2 to type toInt. Maybe I'll just add an overloaded implementation of pleasure and make the conversion explicit, but I was wondering if there was a more elegant and general way to do this, as in the C ++ example above.

+6
interface delegates d d2
source share
3 answers

he_the_great has this mostly correct, but the next small change will make it work with structures / classes that support 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 ); } ); } 
+5
source share

D highlights functions and delegates, because delegates are more than just a pointer to a function. So there is no type that will work for both. Discussed the addition of a wrapper for functions in Phobos (as dsimcha points out, this is std.functional.toDelegate). You can use templates (I don't have access to the latest compiler to check if this works)

 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); } 
+3
source share

As he_the_great mentioned, templates are the best solution in most cases. (The fact that waht std :: function is all the same.) If you cannot / do not want to use templates, look at std.functional. You will find a function called toDelegate() that uses some hidden magic to turn a function pointer into a delegate. Then you can do the following:

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

You can also write something equivalent to C ++ std::function , which is likely to be trivial. In fact, I will do it right here. Note that this does not properly handle ref or out parameters or returns right now due to compiler errors.

 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
source share

All Articles