实例化模板和SWIG

4
我有一个问题不知道如何解决。 我想使用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中执行通常的swig操作:

%{
#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模板放在一个文件中,实例化放在另一个文件中)是解决此问题的唯一方法吗?如果可以避免,我不想创建新文件。

1个回答

3
Warning 401: Nothing known about base class 'EncoderInterface< int >'. Ignored.
Warning 401: Maybe you forgot to instantiate 'EncoderInterface< int >' using %template.
EncoderInterface<int>IntEncoder的基类。SWIG试图为Java包装您的IntEncoder类,但它没有这个基类的包装器,因为它只包装模板的实例化。
在SWIG收到模板基类的名称之前,它不知道如何使Java包装器继承自围绕EncoderInterface<int>的包装器,这就是为什么它会发出警告的原因。

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 的名称与你的另一个类 IntEncoder 相同。
你需要告诉 SWIG 将包装器围绕 EncoderInterface 命名为其他名称,例如 IntEncoderInterface:
%template(IntEncoderInterface) EncoderInterface<int>;

只要是你喜欢的类名,你就可以称它为任何你想要的名称,作为Java API中的类名。
你只能使用SWIG来包装C++模板的实例化,例如,你不能将它们包装成Java泛型类。
如果你还需要不同类型T的EncoderInterface的实例化,你将需要为每个类型添加一个%template声明,告诉SWIG在Java中用不同的类名封装每个类型。
如果你真正需要一个使用Java泛型的自动生成的EncoderInterface的Java包装器,那么你就很遗憾了。如果你需要你的Java API与你的C++ API一致,你将需要探索其他API样式(我看到这是某种序列化接口,但不知道你想要使用API序列化的类型的细节以及在基类中支持的功能,因此无法建议任何特定的替代策略)。
引用:
我读到过一些关于拆分文件的东西(将EncoderInterface模板保留在一个文件中,而将实例化保留在另一个文件中),这是唯一的解决方案吗?如果可以避免创建新文件,我不想这样做。
你所读的可能是建议隐藏模板,使SWIG看不到它或尝试包装它。如果你根本不想包装基类,那么这是一个选项。
你不需要将它放在另一个文件中,你可以使用预处理器来隐藏它(请注意,在这里,IntEncoder从EncoderInterface继承被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*返回类型会被包装为不友好的SWIGTYPE_p_int,这可能不是您想要的。或许可以将decode方法的返回类型改为按值返回(int),这样在Java中就可以直接包装为int了。

1
非常完整的答案。我现在想我明白了,非常感谢! - Bernat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接