3

我找到了这个问题,但一个答案基本上是,你不想这样做:在使用 Swig 为 C++ 代码构建 C# 包装器时,是否可以向现有方法添加代码?

在所描述的情况下,我实际上同意它,其中​​ OP 试图以一种可能很脆弱的方式插入代码。就我而言,我正在按照答案的建议进行操作:重命名方法并使用 %typemap(javacode) 来实现包装方法。

但是我把它写成一个宏,我想重写几个方法,所以我最终多次调用 %typecode(javacode) ,只有最后一个包装方法 javacode typemap 是活动的。

宏的细节很复杂,因为它使用变量 args 来表达签名。

但证明了这个问题:

%define WRAP(CLASS,METHOD)
%rename(method ## _internal,fullname=1) CLASS::METHOD;
%typemap(javamethodmodifiers) CLASS::METHOD "private";
%typemap(javacode) {
    public void METHOD() {
       METHOD ## _internal();  // delegate to original
       // extra code here
    }
}   // (note: dont use %{ %} -- need macro evaluation)
%enddef

WRAP(Foo,bar)
WRAP(Foo,baz)

class Foo {
   void bar();
   void baz();
}

只有公共 void baz() { baz_internal(); ... } 生成。这里的问题是 %rename 和 %typemap(javamethodmodifiers) 是唯一的,因为 CLASS::METHOD 的范围,但 %typemap(javacode) 适用于整个类。如果语法像

 %typemap(javacode,append=true) {   // code   }

得到支持,那么这将解决问题。有没有什么技术可以做到这一点?这对于像 javacode 或 javaimports 这样的类型映射有意义,它们的默认值是空的。

4

2 回答 2

1

我可以制作一个 SWIG 宏来生成您正在寻找的代码。这有点麻烦,但它确实有效。诀窍是滥用 javaout(noblock=1)类型映射而不是 javacode,以便每个函数应用一次,而不是每个类应用一次:

%module test

%define WRAP(CLASS,METHOD)
%rename(METHOD ## _internal,fullname=1) CLASS::METHOD;
%javamethodmodifiers CLASS::METHOD "private";
%typemap(javaout,noblock=1) void CLASS::METHOD {
  {
    $jnicall;
  }

  public void METHOD() {
    METHOD ## _internal();
    // some other bits
  }
}
%enddef

WRAP(Foo,bar)
WRAP(Foo,baz)

class Foo {
public:
   void bar();
   void baz();
};

这会生成您正在寻找的代码,但我怀疑您可以%rename完全跳过并从 javaout 类型映射中完成所有操作。这种方法适用于 SWIG 1.3 及更高版本。

我确实尝试了另一种方法$typemap并复制类型映射,但这最终没有成功。

如果你想支持也返回东西的方法,你需要添加第三个宏参数:

%define WRAP(CLASS,METHOD,RETURN)
%rename(METHOD ## _internal,fullname=1) CLASS::METHOD;
%javamethodmodifiers CLASS::METHOD "private";
%typemap(javaout,noblock=1) RETURN CLASS::METHOD {
    $typemap(javaout,RETURN)

  public $typemap(jstype,RETURN) METHOD() {
    RETURN result = METHOD ## _internal();
    // some other bits
    return result;
  }
}
%enddef

$typemap用于引用默认的、不太专业的类型映射,以避免为非原始/特殊情况返回重复大量代码。

于 2012-08-24T08:07:48.130 回答
1

以下是三个解决方案。将 SOLUTION 的定义更改为 1、2 或 3 以尝试它们中的每一个。

  • SOLUTION 1 使用 SWIG-3.0.12 中添加的 %proxycode 功能,专门解决这个问题。
  • 解决方案 2 使用默认类型映射方法的复制/粘贴/修改。这几乎就是类型映射的全部目的,即采用现有的类型映射并对其进行自定义以获得所需的生成代码。
  • 解决方案 3 在用户类型映射中重用另一个(默认)类型映射的内容。
%module example

#define SOLUTION 1

#if SOLUTION==1
%define WRAP(CLASS,METHOD)
%rename(METHOD ## _internal) CLASS::METHOD;
%typemap(javamethodmodifiers) CLASS::METHOD "private";
//%typemap(javacode) {
%extend CLASS {
%proxycode %{
  public void METHOD() {
     METHOD ## _internal();  // delegate to original
     // extra code here
    System.out.println("extra code in " + #METHOD + " SOLUTION 1");
  }
%}
}
%enddef
#elif SOLUTION==2
%define WRAP(CLASS,METHOD)
%typemap(javaout) void CLASS::METHOD {
    // Next line is copied from java.swg: %typemap(javaout) void
    $jnicall;
    // extra code here
    System.out.println("extra code in " + #METHOD + " SOLUTION 2");
  }
%enddef
#elif SOLUTION==3
%define WRAP(CLASS,METHOD)
%typemap(javaout) void CLASS::METHOD {
    // Next line re-uses/includes the typemap in java.swg: %typemap(javaout) void
    $typemap(javaout, void);
    // extra code here
    System.out.println("extra code in " + #METHOD + " SOLUTION 3");
  }
%enddef
#else
#error "Bad SOLUTION"
#endif

WRAP(Foo,bar)
WRAP(Foo,baz)

%inline %{
class Foo {
public:
   void bar();
   void baz();
};
%}
%{
#include <iostream>
   void Foo::bar() { std::cout << "Foo::bar " << std::endl; }
   void Foo::baz() { std::cout << "Foo::baz " << std::endl; }
%}
于 2019-07-15T18:44:10.287 回答