处理来自 SWIG 中自身专用实例的类继承

Handling class inheritance from specialized instance of self in SWIG

本文关键字:实例 专用 继承 SWIG 处理      更新时间:2023-10-16

我有一些代码可以在C++中编译和工作正常(只要我转发声明通用模板类,然后声明专用实例,然后定义通用模板类 - 请参阅从专业自我类继承? 但是,当我尝试使用 SWIG 将 C# 绑定添加到类时,它要么使 SWIG 崩溃,要么不包含继承类中的方法。 我相信这只能在 C++11 中实现,但我不确定,因为我还没有用较旧的编译器尝试过。

下面是一个玩具示例:

template <typename T, int N = 0> class A;
template <typename T> class A<T, 0>
{
public:
    A() : mFoo(NULL)    {}
    virtual ~A()        {}
    T* getFoo() { return mFoo; }
protected:
    T* mFoo;
};
template <typename T, int N = 0> class A : public A<T, 0>
{
public:
    A() : A<T, 0>(), mBar(N)    {}
    virtual ~A()                {}
    int getBar() const { return mBar; }
protected:
    int mBar;
};

在程序中,我可以实例化A<char,10>的实例(例如(,并可以访问mFoo和mBar,或者只是实例化A的实例而只能访问mFoo。 我还可以使用带有参数的方法,例如

void baz(A<T, 0>* anyA)

该方法将接受A<T, 0>A<T, n>实例。

对于上下文和解释,此模式适用于可以是动态大小或固定大小的容器。 如果它们是动态的,你可以把它实例化为一个A<T, 0>,而没有继承等的开销,或者你可以有一个固定大小的容器(A<T, N>其中 N> 0(,它确实使用继承,但可以访问所有"基"类方法,可以根据需要重写它们,并且仍然被接受为接受容器的动态或固定大小实例的方法的参数。

但是,当我尝试使用 SWIG 以便可以在其他语言中使用此类时,我遇到了问题。

起初,我尝试了类似的东西:

%template(tA) A<char, 0>;

但这会导致 SWIG 崩溃(至少在我当前使用的 3.0.0 版本中(。

接下来,认为像 SWIG 中的所有模板继承一样,我需要为基类和继承器类提供一个现有模板(如果两者都是模板化的(。 所以我尝试了

%template(tABase) A<char, 0>;
%template(tA) A<char>;

这也会导致 SWIG 崩溃。

因此,我试图聪明一点,并利用SWIGS功能为继承自的类使用"无名称"模板,并执行以下操作:

%template() A<char, 0>;
%template(tA) A<char>;

这避免了崩溃,我得到了 tA 类的输出,但它只有继承器类A<T, N>的方法等,实际上并没有从它需要的A<char, 0>专用模板实例继承,因此我无法访问 A<char, 0> 的"基"类中的所有方法和数据。

有没有人试图让SWIG来处理这个问题? 成功? 是否有一个命令行参数可以传递给 SWIG 来使事情正常工作(并阻止它崩溃(?

我能看到的解决你的问题的最简单方法是不要太花哨以至于混淆其他语言,在C++更花哨

template<typename T>
struct A0_impl;
template<typename T, typename N>
struct A_impl;
template<typename T, int N>
struct A_helper {
  typedef A_impl<T,N> type;
};
template<typename T>
struct A_helper<T,0> {
  typedef A0_impl<T> type;
};
template<typename T, int N=0>
using A = typename A_helper<T,N>::type;
template<typename T>
struct A0_impl {
  A0_impl() : mFoo(nullptr)    {}
  virtual ~A0_impl()        {}
  T* getFoo() { return mFoo; }
private:
  T* mFoo;
};
template<typename T, typename N>
struct A_impl:A0_impl<T> {
  A_impl() : A0_impl<T>(), mBar(N) {}
  virtual ~A_impl() {}
  int getBar() const { return mBar; }
protected:
  int mBar;
};
template<typename T>
struct A_impl<T,0>:A0_impl<T> {
  A_impl() : A0_impl<T>() {}
  virtual ~A_impl() {}
  // possibly inherit other constructors from A0_impl
};

这为您提供了C++代码,其行为与您的版本几乎完全相同,但消除了您认为导致问题的专用化后裔问题。

基本上,我用A0_impl替换了您的A<T,0>专用化,并且template别名A<T,N>现在映射到A_impl<T,N>A0_impl<T>,具体取决于N是否0

A template别名是可选的,因为您可以改为A0_impl被称为AnySizedAA_impl被称为 FixedSizeA ,而不是专门A<T,0>做某事,只需禁止它。