我有C++代码,我正在try 使用SWIG提供Java绑定.

struct meters_t : public boost::units::quantity<boost::units::si::length> {};

我希望try 将所有meters_t的引用替换为doubleJava.lang.Double.

我在我的SWIG界面.i文件中try 了以下操作:

%typemap(jstype) meters_t "java.lang.Double"
%typemap(jtype) meters_t "java.lang.Double"
%typemap(jni) meters_t "jdouble"
...
// Duplicated for const, const&, &
%ignore meters_t
%include "my_include.h"

但是,我目前收到一个类型转换错误

error C2440: 'type cast': cannot convert from 'meters_t *' to 'jdouble'
error C2440: 'type cast': cannot convert from `jdouble` to `meters_t *`

有没有人有什么建议来纠正这个错误?我很快就对把meters_t变成简单的double的 idea 失go 了希望:/

UPDATE:个 我还添加了以下内容

%typemap(javain) meters_t "$javainput"

这使Java绑定能够被构建,但是当我try 使用Java绑定时(在一个不同的struct上,它将meters_t作为构造函数arg,它立即抛出一个错误

A fatal error has been detected by the Java Runtime Environment
EXCEPTION_ACCESS_VIOLATION

UPDATE 2.0

我现在有meters_t大口的包装.我的新问题是一个带有Boost默认参数的类,我得到了难以捉摸的Syntax error in input(3).错误

Foo(meters_t meters = meters_t{ 0.0 * boost::units::si::meters });

推荐答案

你已经在正确的轨道上开始了typemaps分.这些对于在C++和Java之间转换类型至关重要.但这些错误表明,SWIG在meters_tjdouble之间的自动转换存在问题.

您可能需要提供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_tdouble之间进行转换来填写转换逻辑.

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这样的复杂库时.

Java相关问答推荐

Android -如何修复Java.time.zone. ZoneRulesExcept:未知时区ID:Europe/Kyiv

Mat. n_Delete()和Mat. n_release的区别

Listview—在Android Java中正确链接项目时出错

inteliJ中是否有一个功能可以自动在块注释中的/*后面添加一个空格?''

流迭代列表<;对象>;上的NoSuchElementException

CompleteableFuture是否运行在不同的内核上?

在Eclipse中数组的可空性

如何读取3个CSV文件并在控制台中按顺序显示?(Java)

在JDK Flight Recorder中只记录单个线程

AWS Java SDK v2.x中没有setObjectAcl方法

从12小时开始的日期模式

记录是类的语法糖吗?

如何在Record Java中使用isRecord()和RecordComponent[]?

我该如何为我的类编写getter和setter方法?

H2数据库仅支持%1个结果集?

如果c不为null,Arrays.sort(T[]a,Comparator<;?super T>;c)是否会引发ClassCastException?

Spring Mapstruct如何获取Lazy初始化实体字段的信息?

转换为JSON字符串时,日期按天递减-Java

将天数添加到ZonedDateTime不会更改时间

从 Java 17 切换回 Java 8 后出现的问题