本文介绍了如何使用SWIG包装std ::函数对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 我已经看过很多类似的问题,但没有找到解决我的特定问题。我试图swigify一些使用std :: function的一些C ++ 11代码,所以我可以在我的Java应用程序中使用它。I have seen quite a few similar questions, but have not found a solution to my particular problem. I am attempting to SWIGify some C++11 code that uses std::function, so I can use it in my Java application.我遇到过这样的共享指针:I have encountered shared pointers like this:virtual std::shared_ptr<some::ns::TheThing> getTheThing(unsigned short thingID);并使用shared_ptr指令成功处理它们:and successfully handled them with the shared_ptr directive like so:%shared_ptr(some::ns::TheThing);我遇到过这样的共享指针的向量:I have encountered vectors of shared pointers like this:virtual std::vector<std::shared_ptr<some::ns::TheThing>> getAllTheThings() const = 0;,并使用以下模板成功处理:and successfully handled them with a template like so:%template(ThingVector) std::vector<std::shared_ptr<some::ns::TheThing>>;现在我有一个这样的方法:Now I have a method like this: void registerThingCallback(std::function<void(std::shared_ptr<some::ns::TheThing>) > func);我不能得到SWIG正确包装。我已经尝试使用%回调,导演,%模板和%内联函数代码,我已经看到了所有这些事情的例子,但没有能够得到任何似乎接近工作。这里是围绕函数调用是否有帮助多一点的上下文(消毒和减少):and I cannot get SWIG to wrap it properly. I have tried using %callback, directors, %template, and %inline functional code, as I have seen examples with all of these things, but have not been able to get anything that seems close to working. Here is a little more context around the function call if that helps (sanitized and reduced):#include <functional>namespace some { namespace ns { /** * Hold some callbacks. */ class ThingCallbacks { public: /** * Registers a callback * @param func The callback function */ void registerThingCallback(std::function<void(std::shared_ptr<some::ns::TheThing>) > func); }; }} 更新 基于Flexo的以下的伟大答案,我更接近一个解决方案。我能够得到下面的例子工作,正如广告。我试着将它并入我的实际代码,但遇到了问题。为了扩展我之前的简化示例,这里是我的TheThing的定义:UpdateBased on Flexo's great answer below, I am much closer to a solution. I was able to get the examples below working exactly as advertised. I tried incorporating it into my actual code, but ran into issues. To expand on my earlier simplified example, here is my definition of TheThing:#ifndef THE_THING_H#define THE_THING_H#include <string>namespace some { namespace ns { class TheThing { public: virtual ~TheThing() {}; virtual unsigned long longThing() const = 0; virtual std::string stringThing() const = 0; }; }}#endif /* THE_THING_H */ $ b b 这里是我的.i文件。为了尽可能少的移动部分,我基本上只是从下面的答案提供的代码中的int和double,并用一个共享指针替换我的对象。And here is my .i file. To have as few moving parts as possible, I've basically just taken the int and double from the code provided in the answer below, and replaced them with a shared pointer to my object.%module(directors="1") Thing%include "stl.i"%include "std_function.i"%include "std_shared_ptr.i"%shared_ptr(some::ns::TheThing);%typemap(javadirectorin) std::shared_ptr<some::ns::TheThing> "new $typemap(jstype, some::ns::TheThing)($1,false)";%typemap(directorin,descriptor="Lsome.ns.typemap(jstype, some::ns::TheThing);") std::shared_ptr<some::ns::TheThing> %{ *($&1_type*)&j$1 = &$1;%}%include "test_thing.h"%include "thing_callback.h"%{#include <memory>#include "test_thing.h"#include "thing_callback.h"%}%std_function(Functor, void, std::shared_ptr<some::ns::TheThing>);%{#include <iostream>void add_and_print(std::shared_ptr<some::ns::TheThing> thing) { std::cout << "here\n";}%}%callback("%s_cb");void add_and_print(std::shared_ptr<some::ns::TheThing>);%nocallback;%inline %{ std::function<void(std::shared_ptr<some::ns::TheThing>)> make_functor() { return [](std::shared_ptr<some::ns::TheThing>){ std::cout << "make functor\n"; }; } void do_things(std::function<void(std::shared_ptr<some::ns::TheThing>)> in) { std::cout << "inside do things\n"; }%} test_thing.h是我刚才发布的,和thing_callback.h是我在原来的问题中发布的代码。这一切都编译通过swig,c ++和Java链没有错误,但看起来像swig有点麻烦连接的c + +和Java之间的点。它创造了这三个类:test_thing.h is what I just posted above, and thing_callback.h is the code I posted in my original question. This all compiles through the swig, c++, and Java chain without error, but it looks like swig is having a little trouble connecting the dots between the c++ and Java. It creates these three classes:SWIGTYPE_p_f_std__function__f_std__shared_ptr__some__ns__TheThing____void____voidSWIGTYPE_p_f_std__shared_ptr__some__ns__TheThing____voidSWIGTYPE_p_std__functionT_void_fstd__shared_ptrT_some__ns__TheThing_tF_t不幸的是,从简单的Java主代码的大多数方法现在接受或返回这些对象,这使它们相当不可用。任何想法如何解决这个?谢谢!And unfortunately, most of the methods from the simple Java main code now take or return these objects, which make them fairly unusable. Any idea how to fix this? Thank you!更完整的细节:我使用以下三个脚本来编译和运行代码。参数略有不同,但我不认为这很重要。在我的目标,它被设置为一个Eclipse maven项目。这些脚本驻留在我的项目的根目录,头和swig文件驻留在src / main / resources,java源文件驻留在src / main / java,java编译的类驻留在target / classes。 Eclipse执行java编译。A little more detail for completeness: I am using the following three scripts to compile and run the code. The parameters are slightly different, but I don't think it matters. On my end it is set up as an Eclipse maven project. These scripts reside in the root of my project, headers and swig files reside in src/main/resources, java source files reside in src/main/java, and java compiled classes reside in target/classes. Eclipse performs the java compilation.MODULE_NAME=ThingPACKAGE=some.nsOUTDIR=./src/main/java/some/nsI_FILE=./src/main/resources/func_thing_test.imvn cleanrm $OUTDIR/*.*mkdir -p $OUTDIRswig -java -c++ -module $MODULE_NAME -package $PACKAGE -outdir $OUTDIR $I_FILE./compileThingSwigTest.sh compileThingSwigTest.shcompileThingSwigTest.sh#!/bin/bashpushd src/main/resourcesg++ -c -std=gnu++11 -fpic \func_thing_test_wrap.cxx \-I/usr/lib/jvm/java/include \-I/usr/lib/jvm/java/include/linuxg++ -shared func_thing_test_wrap.o -o libFunc.sopopd runThingTest.shrunThingTest.shpushd target/classesjava -Xmx512M -Xms512M -Djava.library.path=. some.ns.test.RunThingTestpopd 最后更新 修正了将正确的参数传递给std_function的代码。Last UpdateFixed the code above to pass the right parameters to std_function. Now between the question and answer there is a complete working example of what I was after.推荐答案我们可以这样做工作的。我的回答是我的一个更一般化版本的我的回答前,看这个问题为一个特定的实例和定位Python。We can do this with a bit of work. My answer here is a more generalised version of my a previous of mine answer, looking at this problem for a specific instance and targeting Python.我假设你想要从 std :: function : 我们希望能够从内部调用 std :: function Java代码。 包裹的 std :: function 对象需要像任何其他对象一样传递,包括跨越语言边界 应该可以在Java中写入 std :: function 对象,这可以传递回C ++必须修改在 std :: function 对象上工作的现有C ++代码(即维护 std :: function 交叉语言) 我们应该能够使用C ++指向函数类型的指针在Java中构造 std :: function >We want to be able to call std::function objects from within Java code.The wrapped std::function objects need to get passed around like any other object, including crossing the language boundaries in either direction.It should be possible to write std::function objects inside of Java, which can be passed back to C++ without having to modify existing C++ code that works on std::function objects (i.e. maintaining type erasure of std::function cross language)We should be able to construct std::function objects in Java using C++ pointer to function types.我将通过这些来展示我们如何实现这一点。在可能的情况下,我将保持解决方案语言不可知。I'm going to work through these and show how we can achieve this. Where possible I'll keep the solution language agnostic too.出于讨论的目的,我将忽略您的问题的 shared_ptr 部分,改变事情,因为你有 shared_ptr 工作实际上足以使用它在这种情况下,它只是使我的例子更冗长不必要。For the purposes of discussion I'm glossing over the shared_ptr part of your question, it doesn't actually change things because as you've got shared_ptr working that's actually sufficient to use it in this scenario too, it would just make my examples more verbose needlessly.我正在努力的解决方案实际上是在SWIG中现有的 shared_ptr 支持之后建模的。我已经组合了一个测试界面来说明如何使用它:The solution I'm working towards is actually modelled after the existing shared_ptr support in SWIG. I've put together a test interface to illustrate how it will be used:%module test%include "std_function.i"%std_function(Functor, void, int, double);%{#include <iostream>%}%inline %{ std::function<void(int,double)> make_functor() { return [](int x, double y){ std::cout << x << ", " << y << "\n"; }; }%}基本上使用这里所有你需要做的是include文件std_fucntion.i,然后使用宏%std_function ,其中包含参数:Basically to use this all you need do is include the file "std_fucntion.i" and then use the macro %std_function which takes arguments as:%std_function(Name, Ret, ...)每个要包装的 std :: function 模板的实例化,其中 Name 是你想调用的类型在Java中,Ret是返回类型,然后剩余的(可变参数)参数是您的函数的输入。所以在我的测试界面上面我基本上寻找包装 std :: function< void(int,double)> 。You call this once per instantiation of the std::function template you want to wrap, where Name is what you want to call the type in Java, Ret is the return type and then the remaining (variadic) arguments are the inputs to your function. So in my test interface above I'm basically looking to wrap std::function<void(int,double)>.编写std_function.i的第一个版本并不是太棘手。您需要获得基本工作要求#1和#2的是:Writing a first version of "std_function.i" isn't actually too tricky. All you need to get basic working requirements #1 and #2 is:%{ #include <functional>%}%define %std_function(Name, Ret, ...)%rename(Name) std::function<Ret(__VA_ARGS__)>;%rename(call) std::function<Ret(__VA_ARGS__)>::operator();namespace std { struct function<Ret(__VA_ARGS__)> { // Copy constructor function<Ret(__VA_ARGS__)>(const std::function<Ret(__VA_ARGS__)>&); // Call operator Ret operator()(__VA_ARGS__) const; };}%enddef这包括C ++头文件在生成的包装器代码中一次,然后设置宏以在接口中使用。 SWIG对 C ++ 11可变参数模板的支持并不是非常有用对于我们在这种使用场景中,所以我写的宏基本上重新实现了默认模板扩展功能,使用C99可变参数宏参数(更好的支持)。巧合的是,这意味着我们编写的SWIG代码将与2.x或甚至一些1.3.x版本一起工作。 (我用2.x测试)。即使/当你的SWIG版本确实有%template 支持使用 std :: functionThis includes the C++ header file in the generated wrapper code once and then sets up the macro for usage in interfaces. SWIG's support for C++11 variadic templates isn't actually very helpful for us in this usage scenario, so the macro I wrote basically re-implements the default template expansion functionality using C99 variadic macro arguments (which are much better supported). Coincidentally this means the SWIG code we're writing will work with 2.x or even some 1.3.x releases. (I tested with 2.x). Even if/when your version of SWIG does have %template support that works with std::function retaining this macro is still useful for the rest of the glue that makes it actually callable. std:function 的手动扩展仍然有用,模板仅限于我们关心的用途:实际的 operator()和一个可能派上用场的复制构造函数。The manual expansion of the std:function template is limited to just the bits we care about for our usage: the actual operator() and a copy constructor that might come in handy.唯一要做的事情是将 operator()重命名为与目标语言匹配的内容,例如为Java重命名它只是一个常规函数称为调用,或者如果你的目标是Python __调用__ 或使用tp_slots如果需要。The only other thing to be done is renaming operator() to something that matches the target language, e.g. for Java renaming it to be just a regular function called "call", or if you were targeting Python to __call__ or using tp_slots if required.现在,这足以让我们的界面工作,来证明我写了一点Java:This is now sufficient to let our interface work, to demonstrate it I wrote a little bit of Java:public class run { public static void main(String[] argv) { System.loadLibrary("test"); test.make_functor().call(1,2.5); }}我编译时使用:swig2.0 -Wall -c++ -java test.ig++ -Wall -Wextra -std=c++11 test_wrap.cxx -o libtest.so -I/usr/lib/jvm/default-java/include/ -I/usr/lib/jvm/default-java/include/linux -shared -fPICjavac run.javaLD_LIBRARY_PATH=. java run它工作。要求#4现在很容易越过列表。我们需要做的是告诉SWIG在 std :: function 中有另一个构造函数,它接受兼容的函数指针:Requirement #4 is pretty easy to cross off the list now at this point. All we need to do is tell SWIG there's another constructor in std::function which accepts compatible function pointers:// Conversion constructor from function pointerfunction<Ret(__VA_ARGS__)>(Ret(*const)(__VA_ARGS__));然后我们可以使用 %callback 机制,我们的测试界面文件变为:And then we can use this with the %callback mechanism in SWIG, our test interface file becomes:%module test%include "std_function.i"%std_function(Functor, void, int, double);%{#include <iostream>void add_and_print(int a, double b) { std::cout << a+b << "\n";}%}%callback("%s_cb");void add_and_print(int a, double b);%nocallback;%inline %{ std::function<void(int,double)> make_functor() { return [](int x, double y){ std::cout << x << ", " << y << "\n"; }; }%}然后我们使用的Java :and the Java we use to call this is then:public class run { public static void main(String[] argv) { System.loadLibrary("test"); test.make_functor().call(1,2.5); new Functor(test.add_and_print_cb).call(3,4.5); }}这里我们编译并运行成功。Which we compile and run identically successfully at this point.(请注意,在这一点上创建的一些Java类是以SWIGTYPE_p_f _...开头的,这是正常的, 指针用于函数构造函数和回调常量的类型)(Note that it's normal and desirable to see some Java classes created at this point that start with the name "SWIGTYPE_p_f_..." - these wrap the "pointer to function" types that are used by the pointer to function constructor and callback constants)需求#3是开始获取更棘手。基本上,我们遇到了同样的问题,我先前回答了使SWIG生成Java接口,除了现在我们Requirement #3 is where things start to get trickier. Essentially we've hit the same problem as I answered on making SWIG generate an interface in Java previously, except now we're looking to do it within a macro more generically.事实证明,在这个实例中,因为我们想要生成的接口相当简单,我们可以在宏中使用一些技巧让SWIG为我们生成它。It turns out that in this instance because the interface we want to generate is fairly simple we can use some tricks inside our macro to make SWIG generate it for us.为了使这项工作成功,我们需要做的主要工作是设置SWIG导向器,以提供跨语言多态性,并允许用Java编写的实现C ++接口的东西。这是在我的代码中使用后缀Impl生成的类。The main thing that we need to do in order to make this work is to setup SWIG directors to provide cross-language polymorphism and allow something written in Java to implement a C++ interface. This is the class generated with the suffix "Impl" in my code.为了使Java开发人员感觉正确,我们希望仍然使用C ++和Java实现的相同类型 std :: function 对象。即使 std :: function :: operator()是虚拟的,我们仍然不想让SWIG董事直接使用该类型,因为它通常 std :: function 的值,这将导致类型切片问题。因此,当Java开发人员扩展我们的 std :: function 对象并覆盖调用时,我们需要做一些额外的工作它使得使用该对象的C ++实际上调用Java实现,因为我们不能只使用director来自动处理这个。To make things "feel right" to Java developers we want to still use the same type for both C++ and Java implemented std::function objects. Even if std::function::operator() were virtual we still don't want to have SWIG directors use that type directly as it's pretty common to pass std::function by value which would lead to type slicing problems. So when a Java developer extends our std::function objects and overrides call we need to do some extra work to make it so that C++ which uses that object actually calls the Java implementation given that we can't just use directors to handle this automatically.所以我们做的看起来有点奇怪的。如果你构造一个Java对象,意图实现 std :: function 那么有一个特殊的,受保护的构造函数。这个构造函数留下了 swigCPtr 成员变量,通常指向一个真正的C ++对象为0,而是创建一个匿名包装器对象,实现Impl接口,简单地代理所有的东西到调用成员的Java对象。So what we do looks a little bit weird. If you construct a Java object that is meant to implement std::function then there's a special, protected constructor for that. This constructor leaves the swigCPtr member variable, which normally points to a real C++ object as 0 and instead creates an anonymous wrapper object that implements the "Impl" interface and simply proxies everything back to the call member of the Java object.我们还有一个应用,我们将一个 std :: function 对象传递给C ++。它的作用是检测哪种情况下我们有一个C ++实现的 std :: function 对象,或者Java。在C ++的情况下,它没有什么特别的,一切正常进行。在Java的情况下,它需要代理对象,并要求C ++将其转换回另一个单独的 std :: function 实例,而不是替换。We have another typemap too that gets applied, in Java, everywhere we pass a std::function object to C++. Its role is to detect which case we have - a C++ implemented std::function object, or a Java one. In the C++ case it does nothing special and everything proceeds as normal. In the Java case it takes the proxy object and asks C++ to convert it back to another, separate std::function instance which gets substituted instead.这足以让我们在两种语言中都能找到我们想要的行为,而且没有任何一方感到奇怪的东西(除了很多透明的机械提升)。This is enough to get us the behaviour we want in both languages without anything that feels weird on either side (other than a lot of mechanical lifting that happens transparently).这里的代码是,自动构造代理对象是非常重要的。 Java具有动态代理类作为反射API,但这些只实现接口,不扩展抽象类。我尝试使用的一种可能性是在Java端的 void call(Object ... args),这是一个可变参数。虽然合法,这似乎并没有实际覆盖任何情况下超级类,因为需要。The catch here is that it's non-trivial to automatically construct the proxy object. Java has dynamic proxy classes as part of the reflection API, but these only implement interfaces, not extend abstract classes. One possibility I did try to use was void call(Object ...args) on the Java side, which is a variadic function argument. Whilst legal this didn't seem to actually override any cases in the super class as would be needed.我最后做的是适应一个宏以我想要的方式迭代可变宏参数。这是一个相当明智的解决方案,因为我们已经决定使用可变参数C99宏参数为其他原因。这个机制在我的解决方案中总共使用了四次,一次在函数声明中,一次在Java和C ++的delgated调用中。 (C ++保留了完美的转发属性,Java需要执行一个类型映射查找,所以它们在每种情况下都是不同的)。What I ended up doing was adapting some macros to iterate over variadic macro arguments in the way I wanted. This is a fairly sensible solution given that we already decided to use variadic C99 macro arguments for other reasons. This mechanism gets used four times in total in my solution, once in the function declaration and once in the delgated call for both Java and C++. (C++ has perfect forwarding properties retained and Java needs a typemap lookup to be performed, so they are distinct in each and every case).一些Java代码 - 在void函数中,写入 return other_void_function(); 是不合法的,所以我们需要特殊情况的void函数,如果不是。There's also a custom typemap to simplify some of the Java code - in a void function it's not legal to write return other_void_function();, so we would need to special case void functions if it weren't for that.让我们看看现实中的样子。首先是run.java我用于测试,它只是稍微修改从以前的例子添加一个Java实现的 std :: function 对象。So let's see what that looks like in reality. First up is the run.java I used for testing, it's only slightly modified from previous examples to add a Java implementation of the std::function object.public class run extends Functor { public static void main(String[] argv) { System.loadLibrary("test"); test.make_functor().call(1,2.5); new Functor(test.add_and_print_cb).call(3,4.5); Functor f = new run(); test.do_things(f); } @Override public void call(int a, double b) { System.out.println("Java: " + a + ", " + b); }}现在std_function.iThe std_function.i is now substantially larger with all the changes outlined above:%{ #include <functional> #include <iostream> #ifndef SWIG_DIRECTORS #error "Directors must be enabled in your SWIG module for std_function.i to work correctly" #endif%}// These are the things we actually use#define param(num,type) $typemap(jstype,type) arg ## num#define unpack(num,type) arg##num#define lvalref(num,type) type&& arg##num#define forward(num,type) std::forward<type>(arg##num)// This is the mechanics#define FE_0(...)#define FE_1(action,a1) action(0,a1)#define FE_2(action,a1,a2) action(0,a1), action(1,a2)#define FE_3(action,a1,a2,a3) action(0,a1), action(1,a2), action(2,a3)#define FE_4(action,a1,a2,a3,a4) action(0,a1), action(1,a2), action(2,a3), action(3,a4)#define FE_5(action,a1,a2,a3,a4,a5) action(0,a1), action(1,a2), action(2,a3), action(3,a4), action(4,a5)#define GET_MACRO(_1,_2,_3,_4,_5,NAME,...) NAME%define FOR_EACH(action,...) GET_MACRO(__VA_ARGS__, FE_5, FE_4, FE_3, FE_2, FE_1, FE_0)(action,__VA_ARGS__)%enddef%define %std_function(Name, Ret, ...)%feature("director") Name##Impl;%typemap(javaclassmodifiers) Name##Impl "abstract class";%{ struct Name##Impl { virtual ~Name##Impl() {} virtual Ret call(__VA_ARGS__) = 0; };%}%javamethodmodifiers Name##Impl::call "abstract protected";%typemap(javaout) Ret Name##Impl::call ";" // Suppress the body of the abstract methodstruct Name##Impl { virtual ~Name##Impl();protected: virtual Ret call(__VA_ARGS__) = 0;};%typemap(maybereturn) SWIGTYPE "return ";%typemap(maybereturn) void "";%typemap(javain) std::function<Ret(__VA_ARGS__)> "$javaclassname.getCPtr($javaclassname.makeNative($javainput))"%typemap(javacode) std::function<Ret(__VA_ARGS__)> %{ protected Name() { wrapper = new Name##Impl(){ public $typemap(jstype, Ret) call(FOR_EACH(param, __VA_ARGS__)) { $typemap(maybereturn, Ret)Name.this.call(FOR_EACH(unpack, __VA_ARGS__)); } }; proxy = new $javaclassname(wrapper); } static $javaclassname makeNative($javaclassname in) { if (null == in.wrapper) return in; return in.proxy; } // Bot of these are retained to prevent garbage collection from happenign to early private Name##Impl wrapper; private $javaclassname proxy;%}%rename(Name) std::function<Ret(__VA_ARGS__)>;%rename(call) std::function<Ret(__VA_ARGS__)>::operator();namespace std { struct function<Ret(__VA_ARGS__)> { // Copy constructor function<Ret(__VA_ARGS__)>(const std::function<Ret(__VA_ARGS__)>&); // Call operator Ret operator()(__VA_ARGS__) const; // Conversion constructor from function pointer function<Ret(__VA_ARGS__)>(Ret(*const)(__VA_ARGS__)); %extend { function<Ret(__VA_ARGS__)>(Name##Impl *in) { return new std::function<Ret(__VA_ARGS__)>([=](FOR_EACH(lvalref,__VA_ARGS__)){ return in->call(FOR_EACH(forward,__VA_ARGS__)); }); } } };}%enddef展开以验证 std :: function 对象的Java - > C ++传递并启用控制器:And test.i is slightly expanded to validate the Java -> C++ passing of std::function objects and enable directors:%module(directors="1") test%include "std_function.i"%std_function(Functor, void, int, double);%{#include <iostream>void add_and_print(int a, double b) { std::cout << a+b << "\n";}%}%callback("%s_cb");void add_and_print(int a, double b);%nocallback;%inline %{ std::function<void(int,double)> make_functor() { return [](int x, double y){ std::cout << x << ", " << y << "\n"; }; } void do_things(std::function<void(int,double)> in) { in(-1,666.6); }%}值得注意的是,我们已经编写了大量的Java特定代码 - 虽然如果你的目标是Python的设计将适用于其他语言,使用Python特定的功能来解决这些问题要简单得多。This compiled and ran as with the previous examples. It's worth noting that we've crossed into writing a lot of Java specific code - although the design would work for other languages if you were targeting Python it's a lot simpler to fix some of these issues using Python specific features.我想改进两件事: 使用C ++ 14 variadic lambdas避免宏预处理器魔术我已经用来保持它们兼容C ++ 11。如果你有C ++ 14,%extend 构造函数变成:%extend { function<Ret(__VA_ARGS__)>(Name##Impl *in) { return new std::function<Ret(__VA_ARGS__)>([=](auto&& ...param){ return in->call(std::forward<decltype(param)>(param)...); }); }} 当涉及到使用这个宏与 std :: shared_ptr 如预期的宏本身不需要更改。然而,javadirectorin和directorin类型的应用程序的实现有一个问题,这阻止事情只工作。即使用trunk构建SWIG也是如此。 (结合director和shared_ptr 有一个未解决的问题)When it comes to using this macro with std::shared_ptr as expected the macro itself needs no changes. There is however a problem with the implementation of the javadirectorin and directorin typemaps that get applied, which do prevent things from "just working". This is true even with a build of SWIG from "trunk". (There's an outstanding question on combining directors and shared_ptr)我们可以通过在调用%shared_ptr 后在模块的主要.i文件中添加两个额外的类型:We can work around that though, by adding two additional typemaps in the main .i file of our module right after the call to %shared_ptr:%shared_ptr(some::ns::TheThing);%typemap(javadirectorin) std::shared_ptr<some::ns::TheThing> "new $typemap(jstype, some::ns::TheThing)($1,false)";%typemap(directorin,descriptor="L$typemap(jstype, some::ns::TheThing);") std::shared_ptr<some::ns::TheThing> %{ *($&1_type*)&j$1 = &$1;%}这两个类型的第一个实际上是死代码,调用方法在我们的抽象类中是抽象的,但是更容易修复这个方法的编译,而不是抑制它。第二个类型是很重要的。它基本上类似于正常的out类型,它创建了一个 jlong​​ ,它只是一个C ++指针的表示,即它准备一个对象从C ++, to Java。The first of these two typemaps is actually dead code because we forced the "call" method to be abstract in our abstract class, but it's easier to fix the compilation of this method than it is to suppress it. The second typemap is important. It's substantially similar to the normal "out" typemap in that it creates a jlong which is really just a representation of a C++ pointer, i.e. it prepares an object to go from C++, to Java.请注意,如果您在模块中使用包,则可能需要修改directorin typemap的descriptor属性,要么L $ package $ / $ typemap(...);或者直接用手写。Note that you might need to modify the descriptor attribute of the directorin typemap if you use packages in your module, either to "L$packagepath/$typemap(...);" or simply write it by hand.这应该消除虚假的SWIGTYPE_p_sstd__shared_ptr 。类型现在也生成。如果你有返回shared_ptr对象的虚函数,你需要为它们编写directorout和javadirectorout类型的映射。这些可以基于正常的in类型。This should remove the spurious "SWIGTYPE_p_sstd__shared_ptr..." type generated now as well. If you have virtual functions that return shared_ptr objects you'll need to write directorout and javadirectorout typemaps for them too. These can be base on the normal "in" typemap.这对我自己的简单测试足够了,修改 Functor 工作,至少与我的版本SWIG从树干今天检出。 (我的2.0.x测试失败了,我没有付出太多努力使它工作,因为这是一个已知的工作进行区域)。This was sufficient for my own simple testing with a modified Functor to work, at least with my version of SWIG checked out from the trunk today. (My test with 2.0.x failed and I didn't put much effort into making it work since this is a known work in progress area). 这篇关于如何使用SWIG包装std ::函数对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
09-05 08:06
查看更多