实例化模板和 SWIG

Instantiated templates and SWIG

我有以下问题,我不知道如何解决。 我想使用 SWIG 为同一文件中的这两个 类 创建一个 Java 包装器:

utilities.h:

template<class T>
class EncoderInterface
{
 public:
  virtual ~EncoderInterface()
  {
  }
  virtual const cdap_rib::SerializedObject* encode(const T &object) = 0;
  virtual T* decode(
      const cdap_rib::SerializedObject &serialized_object) const = 0;
};

class IntEncoder : public rib::EncoderInterface<int>
{
 public:
  const cdap_rib::SerializedObject* encode(const int &object);
  int* decode(const cdap_rib::SerializedObject &serialized_object) const;
};

然后我在 .i:

%{
#include "utilities.h"
%}

%include "utilities.h"

它说:

Warning 401: Nothing known about base class 'EncoderInterface< int >'. Ignored.
Warning 401: Maybe you forgot to instantiate 'EncoderInterface< int >' using %template.

如果我尝试像这样使用 %template:

%template(IntEncoder) EncoderInterface<int>;

Warning 302: Identifier 'IntEncoder' redefined (ignored) (Renamed from 'EncoderInterface< int >'),
utilities.h:302: Warning 302: previous definition of 'IntEncoder'.

IntEncoderutilities.cc 中有代码,我想让实用程序的用户创建新的模板实例或使用给定的实例(如果他愿意) .我真的不想更改 IntEncoder 的名称,因此库的任何用户(来自 C++ 或 Java)都将使用相同的名称。

我读过一些关于拆分文件的内容(将 EncoderInterface 模板保存在一个文件中,实例化保存在另一个文件中)这是解决此问题的唯一方法吗?如果可以避免,我不想创建新文件。

Warning 401: Nothing known about base class 'EncoderInterface< int >'. Ignored.
Warning 401: Maybe you forgot to instantiate 'EncoderInterface< int >' using %template.

EncoderInterface<int>IntEncoder 的基数 class。 SWIG 正在尝试为 Java 包装您的 IntEncoder class,但它没有针对此基础 class 的包装器,因为它只包装模板的实例化。

直到 SWIG 为模板基础 class 指定了一个名称,它才知道如何使 IntEncoder 的 Java 包装器派生自 [=14] 的包装器=],这就是它发出警告的原因。

If I try to use the %template thing like this:

%template(IntEncoder) EncoderInterface<int>;

Warning 302: Identifier 'IntEncoder' redefined (ignored) (Renamed from 'EncoderInterface< int >'),
utilities.h:302: Warning 302: previous definition of 'IntEncoder'.

这是正确的想法,但您现在已经告诉 SWIG 调用包装器 EncoderInterface<int> 与其他 class、IntEncoder.[=40= 相同的东西]

您需要告诉 SWIG 在 EncoderInterface<int> 周围调用包装器,例如IntEncoderInterface:

%template(IntEncoderInterface) EncoderInterface<int>;

你可以随心所欲地称呼它,只要它是你喜欢的名字作为你 Java API 中 class 的名字即可。

您只能使用 SWIG 封装 C++ 模板的实例化,您不能,例如,将它们封装为 Java 泛型 classes .

如果您还需要为不同类型 T 实例化 EncoderInterface<T>,则必须为每个类型添加一个 %template 声明,告诉 SWIG 结束他们每个人在 Java.

中都有不同的 class 名字

如果使用 Java 泛型的 EncoderInterface 自动生成的 Java 包装器是您真正想要的,那您就倒霉了。如果您需要 Java API 与您的 C++ API 保持一致,您将不得不探索其他 API 样式(我可以看到这是某种序列化接口,但不知道要用 API 序列化的类型的详细信息,以及基础 class 中支持的功能,但我无法建议任何具体的替代策略)。

I have read something about splitting files (keeping EncoderInterface template in one file and the instantiation in another one) is this the only solution to this problem? I don't want to create new files if I can avoid it.

您阅读的内容可能是在暗示为了对 SWIG 隐藏模板,这样它就不会看到它或尝试包装它。这是一个选项,如果你根本不想包装基础 class。

虽然你不需要把它放在另一个文件中,你可以使用预处理器隐藏它(注意 IntEncoderEncoderInterface<int> 的继承在这里从 SWIG 中隐藏,另外到 EncoderInterface 本身):

#ifndef SWIG
template<class T>
class EncoderInterface
{
 public:
  virtual ~EncoderInterface()
  {
  }
  virtual const cdap_rib::SerializedObject* encode(const T &object) = 0;
  virtual T* decode(
      const cdap_rib::SerializedObject &serialized_object) const = 0;
};
#endif

class IntEncoder
#ifndef SWIG
   : public EncoderInterface<int>
#endif
{
 public:
  const cdap_rib::SerializedObject* encode(const int &object);
  int* decode(const cdap_rib::SerializedObject &serialized_object) const;
};

另请注意,您的 decode 方法中的 int* return 类型将被包装为不友好的 SWIGTYPE_p_int,这可能不是您想要的想。也许 decode 可以 return 按值 (int) 相反,它将直接包装为 int in Java.