如何将Python函数作为C++函数的回调函数

4

这是否意味着您想从C++函数调用Python函数? - Vaughn Cato
你可以将一个C++函数作为另一个C++函数的回调函数,并在其中调用Python函数。 - Gir
@David Robinson:海报明确要求使用boost-python解决方案,因此我认为这是一个有效的问题。 - H. Brandsmeier
@cideous:是哪个海报?这个问题和原始问题都明确要求使用boost::python。 - David Robinson
2个回答

3

我通常用以下方法(并不是唯一的方法)来实现回调函数:

在C++中,我使用一个类来提供以下方式的回调函数:

struct Mesh {
 template<class Visitor>
  void visitChildren(Visitor& v)
  {
     [...]
     v.visit([...])
  }
}

然后当我将这个类导出到Python(仍然是C ++)时

struct ChildrenVisitor 
{
   ChildrenVisitor(PyObject* self)
        : self(self) 
   {}

  void visit( /* .... */ )
  {
    call_method<void>(self, "visit" /*, [...] */ );
  }

 private:
    PyObject* self; // 1
};

访客本身的导出到Python
typedef ChildrenVisitor ClassT;
class_<ClassT, boost::noncopyable >("ChildrenVisitor",
    init<PyObject*>() );

对于Mesh的导出,你需要执行以下操作:

.def("visitChildren", &Mesh::template visitChildren<ChildrenVisitor> )

我通常使用...,这里可以插入任何参数。

在Python中,你可以这样做:

class MyVisitor(ChildrenVisitor): 
  def __init__(self):
    ChildrenVisitor.__init__(self,self)

  def visit(self):
    # do whatever you want

我还喜欢创建一个ChildrenVisitor的子类,它接受Lambda函数,这使得在Python中编写访问者只需要一行代码。
哦,顺便说一下。如果您想在稍后调用该函数,则需要将C++实现更改为以下内容。
struct ChildrenVisitorBase 
{
  virtual void visit( /* .... */ ) = 0;
};

struct Mesh {
  void registerCallback(shared_ptr<ChildrenVisitorBase> v)
  {
     visitors.push_back(v)
  }

  void doSomeWork() {
    // ...
    for(int i=0; i < visitors.size(); ++i)
      visitors[i]->visit( /* ... */ )
  }

  std::vector<  shared_ptr<ChildrenVisitorBase> > visitors;
}

ChildrenVisitor 实现 ChildrenVisitorBase 接口。

0

你的问题可以在这个示例中找到答案。

如果你想要作为回调函数的函数在编译时已知,那么应该使用PyEval_CallObject(...);。如果函数必须在运行时定义,则使用示例中所示的方案来接收函数指针。


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