swig:扩展类模板以提供__str__

时间:2014-08-11 15:04:22

标签: python c++ swig

假设您有一个模板类Foo,并且您希望透明地使用Swig包装它,以便您可以打印该类:

>>> from example import *
>>> f = Foo2()
>>> print(f)
In Foo class!

我已关注this postthis one。所以我的头文件是:

#include <iostream>

template <int d> class Foo {

public:

  friend std::ostream &operator<<(std::ostream &os, const Foo &m) {
    os << "Inside Foo class!" << std::endl;
    return os;
  }
};

我的界面文件:

%{
#include <sstream>
#include <iostream>
#include "foo.hpp"
%}

%include "std_iostream.i"

// Try grabbing it unmodified
%include "foo.hpp"


/* Instantiate a few different versions of the template */
%template(Foo2) Foo<2>;
%template(Foo3) Foo<3>;


%extend Foo<2> {

  const char *__str__() {

    std::ostringstream oss(std::ostringstream::out);
    oss << *self;
    return oss.str().c_str();
  }
};

所以这很好用,我可以像以前一样打印对象,但是我想将它概括为模板参数的任何值,因为复制每个模板参数的代码都没有意义。我在界面文件中尝试了以下操作,但它没有工作:

template <int d> class Foo {

public:

  %extend {
    const char *__str__() {

      std::ostringstream oss(std::ostringstream::out);
      oss << *self;
      return oss.str().c_str();
    }
  }
};

2 个答案:

答案 0 :(得分:3)

您可以通过省略模板参数列表,从其定义之外%extend %extend Foo { const char *__str__() { std::ostringstream oss(std::ostringstream::out); oss << *self; return oss.str().c_str(); } }; %template(Foo2) Foo<2>; %template(Foo3) Foo<3>; 主模板:

%define WRAP_FOO(N)

  %template( Foo ## N ) Foo<N>;

  %extend Foo<N> {
    const char *__str__() {
      std::ostringstream oss(std::ostringstream::out);
      oss << *self;
      return oss.str().c_str();
    }
  };

%enddef

/* Instantiate a few different versions of the template */
WRAP_FOO(2)
WRAP_FOO(3)

或者您可以使用SWIG宏一次性包装和扩展每个专业化:

.c_str()

请注意,在任何一种情况下,您都会通过返回在函数返回之前销毁的std::string的{​​{1}}结果来导致未定义的行为。

答案 1 :(得分:1)

您在最后一个示例中使用的%extend语法应该是正确的,这是我们在OpenStudio中使用的一种技术

我认为问题在于您定义模板2次,一次在%import指令中,一次在.i文件中。第一个定义是SWIG正在使用的定义。

虽然不理想,但我相信您需要删除%include "foo.hpp"指令并明确定义所需的接口。您的新.i文件现在变为:

%{
#include <sstream>
#include <iostream>
#include "foo.hpp"
%}

%include "std_iostream.i"

// Don't let SWIG directly parse foo.hpp
// %include "foo.hpp"



template <int d> class Foo {

public:
  // include here prototypes for all functions
  // you want exposed. You don't need the implementation like in 
  // a normal C++ template declaration

  // include here any extensions you want to add
  %extend {
    const char *__str__() {

      std::ostringstream oss(std::ostringstream::out);
      oss << *self;
      return oss.str().c_str();
    }
  }
};

/* Instantiate a few different versions of the template */
%template(Foo2) Foo<2>;
%template(Foo3) Foo<3>;

或者,您可以直接将SWIG代码放在hpp文件中,而不必维护两个API:

新的.i文件:

%{
#include <sstream>
#include <iostream>
#include "foo.hpp"
%}

%include "std_iostream.i"

// let swig directly parse foo.hpp
%include "foo.hpp"


/* Instantiate a few different versions of the template */
%template(Foo2) Foo<2>;
%template(Foo3) Foo<3>;

新的.hpp文件:

#include <iostream>

template <int d> class Foo {

public:
#ifdef SWIG
  %extend {
    const char *__str__() {

      std::ostringstream oss(std::ostringstream::out);
      oss << *self;
      return oss.str().c_str();
    }
  }
#endif

  friend std::ostream &operator<<(std::ostream &os, const Foo &m) {
    os << "Inside Foo class!" << std::endl;
    return os;
  }
};