你已经在正确的轨道上开始了typemaps分.这些对于在C++和Java之间转换类型至关重要.但这些错误表明,SWIG在meters_t
和jdouble
之间的自动转换存在问题.
您可能需要提供custom个类型映射来显式处理此转换.您需要提供一种方法,让SWIG了解如何将meters_t
转换为jdouble
,反之亦然.
try 执行%typemap(in)
和%typemap(out)
来代替meters_t
.这些类型映射将定义在从C++传递到Java时如何将meters_t
对象转换为Java double
,反之亦然.
SWIG对解析复合体default arguments的支持有限].一种解决方案是简化swg接口文件中的默认参数,或者提供一个重载版本的构造函数,而不使用swg的默认参数来包装.
在你的SWIG interface file中,实现类型映射:
%typemap(in) meters_t {
// Code to convert from jdouble to meters_t
}
%typemap(out) meters_t {
// Code to convert from meters_t to jdouble
}
// For the constructor issue
%ignore Foo::Foo(meters_t);
%extend Foo {
Foo() {
return new Foo(meters_t{0.0 * boost::units::si::meters});
}
}
您需要根据如何在meters_t
和double
之间进行转换来填写转换逻辑.
Java Side JNI Bridge C++ Side
────────── ────────── ────────
jdouble | meters_t Object
(double) | |
| | |
| [ JNI Conversion ] | |
|---------------------------->| |
| | Construct meters_t |
| | using jdouble value |
| |<--------------------------|
| | |
| | Extract double |
| | value from meters_t |
| |-------------------------->|
| | |
|<----------------------------| |
| | |
Regarding "Code to convert from jdouble to meters_t
", when converting from Java to C++, you will receive a Java double
(represented as jdouble
in C++ JNI code). You need to convert this to a meters_t
object.
Assuming meters_t
can be constructed or assigned from a double
, the typemap might look like this:
%typemap(in) meters_t {
$1 = meters_t($input * boost::units::si::meter);
}
在此类型映射中:
$1
是C++参数的占位符(在本例中为meters_t
).
$input
表示来自Java(A jdouble
)的输入.
- 假设
meters_t
可以用这种方式初始化,则表达式$input * boost::units::si::meter
从Java Double构造一个meters_t
对象.
就"Code to convert from meters_t to jdouble
"而言:
从C++转换到Java时,您需要从meters_t
对象中提取一个double
值:
%typemap(out) meters_t {
$result = (jdouble)$1.value();
}
在此类型映射中:
$1
是C++meters_t
对象的占位符.
$result
是您要映射到的Java类型的JNI表示(在本例中为jdouble
).
$1.value()
是从meters_t
对象中提取double
值的假设方法或方式.您需要将其替换为从meters_t
类型中提取数值的实际方法或途径.
Make sure that meters_t
can be constructed from a double
and has a method to extract its value as a double
. If not, you will need to adapt the code to suit the actual interface of meters_t
.
These typemaps assume that boost::units::si::meter
is the appropriate unit for conversion. Adjust if necessary based on your specific implementation of meters_t
.
Unfortunately this has not corrected my current outstanding issue. I have actually already attempted what you suggested with ignoring the constructor and providing another.
C:\my_project\src\inc\foo.h(line of the foo ctor): Syntax error in input(3)
. Given the error is in the foo.h
, I feel like SWIG is unable to parse the default argument for whatever reason, where ignoring the code will not help; I imagine SWIG reading foo.h is independent of any directives in the SWIG Interface file?
错误Syntax error in input(3)
确实表明SWIG在解析头文件中的C++代码时遇到了问题,特别是foo.h
中带有默认参数的构造函数.当C++代码中使用的语法或 struct 太复杂或太陌生而无法接受时,就会发生这种情况.
如果可能的话,简化C++头文件中的构造函数.这意味着以SWIG可以理解的方式删除或修改默认参数.例如,你可以将构造函数分成两个:一个没有参数,另一个有一个meters_t
参数,在实现中而不是在声明中处理默认情况.
// Original:
// Foo(meters_t meters = meters_t{ 0.0 * boost::units::si::meters });
// Simplified:
Foo();
Foo(meters_t meters);
创建专门用于swg的构造函数的重载版本.该版本不会有复杂的默认参数.使用SWIG's %ignore
directive可忽略有问题的构造函数并仅公开简化版本.
在您的SWIG界面文件中:
%ignore Foo::Foo(meters_t meters = meters_t{ 0.0 * boost::units::si::meters });
%extend Foo {
Foo() {
return new Foo(meters_t{0.0 * boost::units::si::meters});
}
}
您还可以使用%inline
直接在界面文件中提供问题代码的替代、易用版本.这允许您保持原始的C++代码不变,但提供了一个简化的版本供SWIG处理.
%inline %{
class Foo {
public:
Foo() : Foo(meters_t{0.0 * boost::units::si::meters}) {}
Foo(meters_t meters) { /* Constructor implementation */ }
};
%}
关键是创建一个SWIG可以解析的接口,而不会丢失Java绑定中所需的功能.
Yeah, modifying the ctor
to provide a Foo()
and Foo(meters_t meters)
, where moving the initialisation of Foo::meters (meters = meters_t{ 0.0 * boost::units::si::meters })
to Foo.cpp
corrects the issue.
I would really much prefer to SWIG wrap the code in question without having to alter the source code.
I feel like I am missing a boost header, but I have added the includes used in the .h
file into my SWIG interface %module MyModule { //some boost headers }
. In short, SWIG does not know what boost::units::si::meter
is when it reads Foo.h
!?
我同意:您最好不要修改原始的C++源代码来适应SWIG.这个问题(SWIG不能识别boost::units::si::meter
)可能是由于SWIG对复杂的C++ struct 的理解有限,特别是来自像Boost这样的库.
在SWIG接口文件中包含Boost头文件是一个很好的开始.然而(同样),SWIG可能无法完全理解或解析复杂的Boost struct .确保在SWIG接口文件中包含必要的Boost头文件,类似于它们在C++头文件中的包含方式(尽管对于Boost中的复杂模板类型,这可能并不总是可行).
%module MyModule
%{
#include "foo.h"
#include <boost/units/systems/si/length.hpp>
#include <boost/units/systems/si/prefixes.hpp>
%}
As mentioned before, use %ignore
to exclude the problematic constructor from SWIG's processing.
Then, either use %extend
to define a SWIG-friendly version of the constructor or %rename
to expose a different, simplified constructor to Java.
%ignore Foo::Foo(meters_t meters = meters_t{ 0.0 * boost::units::si::meters });
作为最后的手段,如果SWIG在Boost类型方面遇到困难,可以考虑用C++创建一个包装类,为SWIG提供一个更简单的接口.该包装器将在内部处理Boost类型和复杂性,只公开对SWIG友好的类型和方法.
- 创建一个
FooWrapper
类来简化SWIG的界面.
- 在
FooWrapper
内,管理复杂的Boost交互,提供更简单的SWIG方法.
class FooWrapper {
public:
FooWrapper() : foo(0.0 * boost::units::si::meters) {}
explicit FooWrapper(double meters) : foo(meters * boost::units::si::meters) {}
private:
Foo foo;
};
然后在SWIG界面文件中:
%include "FooWrapper.h"
我们的目标仍然是在保留原始C++源代码和为SWIG提供它可以理解的形式之间找到平衡.在这种情况下,为SWIG创建一个简化的界面或包装器通常是一个实用的解决方案,尤其是在处理像Boost这样的复杂库时.