digitalmars.D.learn - extern (c++) std::function?
- Etienne Cimon (4/4) Aug 14 2014 I'm looking into making a binding for the C++ API called Botan, and the
- FreeSlave (9/13) Aug 15 2014 There are some restrictions about sharing complex types between
- =?ISO-8859-1?Q?R=E9my_Mou=EBza?= (75/84) Aug 15 2014 You'll certainly have to make a C++ wrapper. However, a delegate being
- Etienne (3/6) Aug 16 2014 Thanks for the detailed answer, this is the direction I'm going to be
I'm looking into making a binding for the C++ API called Botan, and the constructors in it take a std::function. I'm wondering if there's a D equivalent for this binding to work out, or if I have to make a C++ wrapper as well?
Aug 14 2014
On Friday, 15 August 2014 at 03:10:43 UTC, Etienne Cimon wrote:I'm looking into making a binding for the C++ API called Botan, and the constructors in it take a std::function. I'm wondering if there's a D equivalent for this binding to work out, or if I have to make a C++ wrapper as well?There are some restrictions about sharing complex types between C++ and D. Currently only POD-structs and classes with virtual functions are supported for transparent interaction. In this case things become even more complicated since std::function is template class and D can't instantiate C++ templates. You should stick with some predefined signatures and make wrappers on C++ side, which will accept 'plane' functions and construct std::function.
Aug 15 2014
You'll certainly have to make a C++ wrapper. However, a delegate being implemented as a struct containing a context pointer and a function, you can get some degree of interoperability between C++ and D (BUT note that it is an undocumented implementation detail subject to change without notice -- althought it hasn't changed in many years): /* =========================================================== */ /// ddg.d import std.stdio; import std.string; /// A C++ function that will take a D delegate. extern (C) void callDg (immutable(char)* delegate (int, int)); /// A dummy class. class X { /// This method can be used as a delegate. extern (C) immutable(char)* callMe (int i, int j) { return "%d, %d".format (i, j).toStringz; } } void main () { auto x = new X; callDg (&x.callMe); } /* =========================================================== */ /// cpp_dg.cpp #include <iostream> using namespace std; /// A D delegate representation in C++. struct Dg { /// The context pointer. void * ctx; /// The function within the delegate: the first argument is the context pointer. const char *(*dg) (void * ctx, int i, int j); /// C++ sugar: calling a struct Dg as a function. const char * operator ()(int i, int j) { return dg (ctx, i, j); } }; /// Extern C allows D compatibilty. extern "C" { void callDg (Dg dg) { /// Call the extern (C) D delegate. cout << dg (42, 7) << endl; } } /* =========================================================== */ $ g++ -c cpp_dg.cpp $ dmd ddg.d cpp_dg.o -L-lstdc++ $ ./ddg 42, 7 /* =========================================================== */ According to http://en.cppreference.com/w/cpp/utility/functional/function: "Class template std::function is a general-purpose polymorphic function wrapper. Instances of std::function can store, copy, and invoke any Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members." Thus the struct Dg in the example above should be compatible with the Botan constructors. Also, extern (C) delegates are not that convenient in D, especially with assignments of anonymous/inline ones. You may want to add a layer of abstraction to the API you expose in D so that user D delegates are used from a second extern (C) delegate itself used by the C++ wrapper: class BotanStuff { protected void delegate (string) ddg; protected BotanWrapper wrapr; this (void delegate (string) dg) { ddg = dg; wrapr = new BotanWrapper (& this.cppDg); } extern (C) void cppDg (immutable(char)* cStr) { import std.conv; dg (cStr.to!string); } } If you are planning to use Swig for your binding, this kind of wrapping may be conveniently done using custom typemaps. On 08/15/2014 05:10 AM, Etienne Cimon wrote:I'm looking into making a binding for the C++ API called Botan, and the constructors in it take a std::function. I'm wondering if there's a D equivalent for this binding to work out, or if I have to make a C++ wrapper as well?
Aug 15 2014
On 2014-08-15 6:12 AM, Rémy Mouëza wrote:assignments of anonymous/inline ones. You may want to add a layer of abstraction to the API you expose in D so that user D delegates are used from a second extern (C) delegate itself used by the C++ wrapper:Thanks for the detailed answer, this is the direction I'm going to be taking!
Aug 16 2014