带有模板类的 SWIG SHARED_PTR 宏

Posted

技术标签:

【中文标题】带有模板类的 SWIG SHARED_PTR 宏【英文标题】:SWIG_SHARED_PTR macro with templated class 【发布时间】:2011-04-05 22:06:18 【问题描述】:

我正在使用带有 boost 共享指针的 SWIG 来创建 python 扩展。我当前的问题是 SWIG_SHARED_PTR 宏似乎与模板类的工作方式不同。我会举两个例子,一个没有模板(example),一个有模板(example2)。

首先我将包含代码,最后展示两个扩展在 python 中的行为差异。

基本问题是没有模板共享指针在python中显示为

<example.Derived; proxy of <Swig Object of type 'derived_sptr *' at 0xb772c4b8> >

而当包装的类是实例化模板时,显示为

<Swig Object of type 'derived_int_sptr *' at 0xb787e4b8>

我是 C++ 模板的新手,所以很可能我遇到的问题与 SWIG 无关。

没有模板(工作正常)

example.h

#include <boost/shared_ptr.hpp>                                                                                                

#ifndef EXAMPLE_H                                                                                                              
#define EXAMPLE_H                                                                                                              

class Base                                                                                                                    
 public:                                                                                                                       
  Base(int number1);                                                                                                           
  int get_number1();                                                                                                           
  virtual int get_number2() = 0;                                                                                               
 protected:                                                                                                                    
  int number1;                                                                                                                 
;                                                                                                                             

class Derived : public Base                                                                                                   
 public:                                                                                                                       
  Derived(int number1, int number2);                                                                                           
  int get_number2();                                                                                                           
 private:                                                                                                                      
  int number2;                                                                                                                 
;                                                                                                                             

typedef boost::shared_ptr<Base> base_sptr;                                                                                     
typedef boost::shared_ptr<Derived> derived_sptr;                                                                               

derived_sptr make_derived(int number1, int number2);                                                                           

int get_number1(base_sptr b);                                                                                                  

#endif

example.cc

#include "example.h"                                                                                                       

Base::Base(int number1) :                                                                                                  
  number1(number1)                                                                                                         
                                                                                                                         

int Base::get_number1()                                                                                                   
  return number1;                                                                                                          
                                                                                                                          

Derived::Derived(int number1, int number2) :                                                                               
  Base(number1),                                                                                                           
  number2(number2)                                                                                                         
                                                                                                                         

int Derived::get_number2()                                                                                                
  return number2;                                                                                                          
                                                                                                                          

derived_sptr make_derived(int number1, int number2)                                                                       
  return derived_sptr(new Derived(number1, number2));                                                                      
                                                                                                                          

int get_number1(base_sptr b)                                                                                              
  return b->get_number1();                                                                                                 

example.i

%module example                                                                                                            
%                                                                                                                         
  #include "example.h"                                                                                                     
%                                                                                                                         

%include boost_shared_ptr.i                                                                                                

SWIG_SHARED_PTR(base_sptr, Base)                                                                                           
SWIG_SHARED_PTR_DERIVED(derived_sptr, Base, Derived)                                                                       

%include example.h                                                                                                         

使用模板(不起作用)

example2.h

#include <boost/shared_ptr.hpp>                                                                                            

#ifndef EXAMPLE2_H                                                                                                          
#define EXAMPLE2_H                                                                                                          

template <typename T>                                                                                                      
class Base                                                                                                                
 public:                                                                                                                   
  Base(T number1);                                                                                                         
  T get_number1();                                                                                                         
  virtual T get_number2() = 0;                                                                                             
 protected:                                                                                                                
  T number1;                                                                                                               
;                                                                                                                         

template <typename T>                                                                                                      
class Derived : public Base<T>                                                                                            
 public:                                                                                                                   
  Derived(T number1, T number2);                                                                                           
  T get_number2();                                                                                                         
 private:                                                                                                                  
  T number2;                                                                                                               
;                                                                                                                         

typedef Base<int> base_int;                                                                                                
typedef Derived<int> derived_int;                                                                                          

typedef boost::shared_ptr<base_int> base_int_sptr;                                                                         
typedef boost::shared_ptr<derived_int> derived_int_sptr;                                                                   

derived_int_sptr make_derived_int(int number1, int number2);                                                               

int get_number1_int(base_int_sptr b);          

#endif

example2.cc

#include "example2.h"                                                                                                       

template <typename T>                                                                                                      
Base<T>::Base(T number1) :                                                                                                 
  number1(number1)                                                                                                         
                                                                                                                         

template <typename T>                                                                                                      
T Base<T>::get_number1()                                                                                                  
  return number1;                                                                                                          
                                                                                                                          

template <typename T>                                                                                                      
Derived<T>::Derived(T number1, T number2) :                                                                                
  Base<T>(number1),                                                                                                        
  number2(number2)                                                                                                         
                                                                                                                         

template <typename T>                                                                                                      
T Derived<T>::get_number2()                                                                                               
  return number2;                                                                                                          
                                                                                                                          

template class Base<int>;                                                                                                  
template class Derived<int>;                                                                                               

derived_int_sptr make_derived_int(int number1, int number2)                                                               
  return derived_int_sptr(new Derived<int>(number1, number2));                                                             
                                                                                                                          

int get_number1_int(base_int_sptr b)                                                                                      
  return b->get_number1();                                                                                                 
 

example2.i

%module example2                                                                                                            
%                                                                                                                         
  #include "example2.h"                                                                                                     
%                                                                                                                         

%include boost_shared_ptr.i                                                                                                

SWIG_SHARED_PTR(base_int_sptr, base_int)                                                                                   
SWIG_SHARED_PTR_DERIVED(derived_int_sptr, base_int, derived_int)                                                           

%include example.h                                                                                                         

%template(base_int) Base<int>;                                                                                             
%template(derived_int) Derived<int>;                                                                                       

差异示例:

> import example
> d = example.make_derived(4, 5)
> d
> <example.Derived; proxy of <Swig Object of type 'derived_sptr *' at 0xb77327a0> >
> d.get_number1()
4
> example.get_number1(d)
4
> import example2
> d = example2.make_derived_int(4, 5)
> d
<Swig Object of type 'derived_int_sptr *' at 0xb787e4b8>
> d.get_number1()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'SwigPyObject' object has no attribute 'get_number1'
> example.get_number1_int(d)
4

【问题讨论】:

【参考方案1】:

SWIG 对于对象暴露给它的顺序可能非常敏感,它具有内部类型系统。

尝试移动您的 %template 语句,使其位于您的 SWIG_SHARED_PTR 语句之前。

【讨论】:

如果这样做,我会收到错误消息:example.i:7: Error: Template 'Base' undefined。 example.i:8:错误:模板“派生”未定义。 example.i:11: Warning(303): %extend 为未声明的类 derived_int 定义。我的理解是 %template 语句需要在模板定义之后出现,但 SWIG_SHARED_PTR 宏需要提前出现。我会继续玩订购,看看我能不能得到一些工作。感谢您的建议。 我发现了问题。感谢您的建议,它为我指明了正确的方向。【参考方案2】:

在 example2.i 中的行

SWIG_SHARED_PTR(base_int_sptr, base_int) 
SWIG_SHARED_PTR_DERIVED(derived_int_sptr, base_int, derived_int)

应该替换为

SWIG_SHARED_PTR(base_int_sptr, Base<int>)                              
SWIG_SHARED_PTR_DERIVED(derived_int_sptr, Base<int>, Derived<int>)

【讨论】:

以上是关于带有模板类的 SWIG SHARED_PTR 宏的主要内容,如果未能解决你的问题,请参考以下文章

如何用 swig 实例化模板类的模板方法?

swig shared_ptr 导致一个不透明的对象

SWIG:如何从 SwigPyobject 获取包装的 std::shared_ptr 的值

带有类型推导的 swig python 模板函数

shared_ptr智能指针模板类的简单实现(c++11)

shared_ptr智能指针模板类的简单实现(c++11)