【问题标题】:Handling class inheritance from specialized instance of self in SWIG在 SWIG 中处理来自特定 self 实例的类继承
【发布时间】:2014-04-10 22:42:35
【问题描述】:

我有一些代码可以在 C++ 中编译并正常工作(只要我转发声明通用模板类,然后是专用实例,然后定义通用模板类 - 请参阅 inheriting from class of specialized self?)。但是,当我尝试使用 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&lt;char,10&gt; 的实例(例如),并且可以访问mFoo 和mBar,或者只是实例化A 的实例并且只能访问mFoo。我也可以使用带有参数的方法,例如

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

并且该方法将接受A&lt;T, 0&gt;A&lt;T, n&gt; 实例。

对于上下文和解释,此模式适用于动态或固定大小的容器。如果它们是动态的,您可以将其实例化为 A&lt;T, 0&gt; 而没有继承等开销,或者您可以拥有一个使用继承但具有固定大小的容器 (A&lt;T, N&gt; 其中 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&lt;T, N&gt; 的方法等,实际上并没有从它需要的 A&lt;char, 0&gt; 专用模板实例继承因此我无法访问A&lt;char, 0&gt; 的“基”类中的所有方法和数据。

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

【问题讨论】:

    标签: c++ inheritance c++11 swig template-specialization


    【解决方案1】:

    我认为解决您的问题的最简单方法是不要过于花哨以至于混淆其他语言,而是通过更喜欢 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&lt;T,0&gt; 专业化,并且template 别名A&lt;T,N&gt; 现在映射到A_impl&lt;T,N&gt;A0_impl&lt;T&gt;,具体取决于N 是否为0

    A template 别名是可选的,因为您可以改为将 A0_impl 称为 AnySizedA 并将 A_impl 称为 FixedSizeA,而不是专门为 A&lt;T,0&gt; 做某事而简单地禁止它.

    【讨论】:

    • 事实证明,这基本上是我最终解决它的方式 - 将 A 重命名为不同的类名。唯一的问题是我必须遍历代码库的其余部分并将 A 的所有方法参数替换为新基类的名称。令人沮丧的是,为了满足 SWIG,我不得不进行如此多的代码更改。幸运的是,我确实可以访问库源代码并且可以进行更改。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-10
    • 1970-01-01
    • 2020-05-18
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多