Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过引用通过使用pybind11的虚拟函数传递std::vector时出现问题 我有一些C++代码绑定到Python,我们通过一个虚拟方法传递STD::vector引用一个奇怪的问题,并对那个STD::vector坚持在该方法之外。< /P> 我们想做的是提供一个C++纯虚函数,它接受引用的STD::vector,这样一个重写该方法的Python类可以修改STD::vector,把它交还给其他C++代码。我们正在遵循关于生成的方法,但是在我们的测试中,我们发现STL向量在Python中创建STL向量时被适当修改并通过引用传递,但是如果我们在C++中创建STD::vector,则不是。_Python_C++_Stdvector_Pybind11 - Fatal编程技术网

通过引用通过使用pybind11的虚拟函数传递std::vector时出现问题 我有一些C++代码绑定到Python,我们通过一个虚拟方法传递STD::vector引用一个奇怪的问题,并对那个STD::vector坚持在该方法之外。< /P> 我们想做的是提供一个C++纯虚函数,它接受引用的STD::vector,这样一个重写该方法的Python类可以修改STD::vector,把它交还给其他C++代码。我们正在遵循关于生成的方法,但是在我们的测试中,我们发现STL向量在Python中创建STL向量时被适当修改并通过引用传递,但是如果我们在C++中创建STD::vector,则不是。

通过引用通过使用pybind11的虚拟函数传递std::vector时出现问题 我有一些C++代码绑定到Python,我们通过一个虚拟方法传递STD::vector引用一个奇怪的问题,并对那个STD::vector坚持在该方法之外。< /P> 我们想做的是提供一个C++纯虚函数,它接受引用的STD::vector,这样一个重写该方法的Python类可以修改STD::vector,把它交还给其他C++代码。我们正在遵循关于生成的方法,但是在我们的测试中,我们发现STL向量在Python中创建STL向量时被适当修改并通过引用传递,但是如果我们在C++中创建STD::vector,则不是。,python,c++,stdvector,pybind11,Python,C++,Stdvector,Pybind11,下面是一个自包含的示例,演示了这个问题。首先是C++ PybDun11代码,在这里我们创建一个抽象基类 A,用一个纯纯方法>代码>::FUNC,我们想从Python中重写: #include "pybind11/pybind11.h" #include "pybind11/stl_bind.h" #include "pybind11/stl.h" #include "pybind11/functional.h" #include "pybind11/operators.h" #include

下面是一个自包含的示例,演示了这个问题。首先是C++ PybDun11代码,在这里我们创建一个抽象基类<代码> A<代码>,用一个纯纯方法>代码>::FUNC</代码>,我们想从Python中重写:

#include "pybind11/pybind11.h"
#include "pybind11/stl_bind.h"
#include "pybind11/stl.h"
#include "pybind11/functional.h"
#include "pybind11/operators.h"

#include <iostream>
#include <vector>

namespace py = pybind11;
using namespace pybind11::literals;

PYBIND11_MAKE_OPAQUE(std::vector<int>)

//------------------------------------------------------------------------------
// The C++ types and functions we're binding
//------------------------------------------------------------------------------
struct A {
  virtual void func(std::vector<int>& vec) const = 0;
};

// In this function the std::vector "x" is not modified by the call to a.func(x)
// The difference seems to be that in this function we create the std::vector
// in C++
void consumer(A& a) {
  std::vector<int> x;
  a.func(x);
  std::cerr << "consumer final size: " << x.size() << std::endl;
}

// Whereas here, with the std::vector<int> created in Python and passed in, the
// std::vector "x" is modified by the call to a.func(x).
// The only difference is we create the std::vector in Python and pass it in here.
void another_consumer(A& a, std::vector<int>& x) {
  std::cerr << "another_consumer initial size: " << x.size() << std::endl;
  a.func(x);
  std::cerr << "another_consumer final size  : " << x.size() << std::endl;
}

//------------------------------------------------------------------------------
// Trampoline class for A
//------------------------------------------------------------------------------
class PYB11TrampolineA: public A {
public:
  using A::A;
  virtual void func(std::vector<int>& vec) const override { PYBIND11_OVERLOAD_PURE(void, A, func, vec); }
};

//------------------------------------------------------------------------------
// Make the module
//------------------------------------------------------------------------------
PYBIND11_MODULE(example, m) {
  py::bind_vector<std::vector<int>>(m, "vector_of_int");

  {
    py::class_<A, PYB11TrampolineA> obj(m, "A");
    obj.def(py::init<>());
    obj.def("func", (void (A::*)(std::vector<int>&) const) &A::func, "vec"_a);
  }

  m.def("consumer", (void (*)(A&)) &consumer, "a"_a);
  m.def("another_consumer", (void (*)(A&, std::vector<int>&)) &another_consumer, "a"_a, "x"_a);
}
执行Python示例将导致:

--------------------------------------------------------------------------------
consumer(b) -- This one seems to fail to pass back the modified std::vector<int> from B.func
B.func START:  vector_of_int[]
B.func STOP :  vector_of_int[-1]
consumer final size: 0        
--------------------------------------------------------------------------------
another_consumer(b, x) -- This one works as expected
another_consumer initial size: 0
B.func START:  vector_of_int[]
B.func STOP :  vector_of_int[-1]
another_consumer final size  : 1
x :  vector_of_int[-1]            
--------------------------------------------------------------------------------
消费者(b)——这一个似乎无法从b.func传回修改过的std::vector
B.func START:vector_of_int[]
B.func-STOP:int[-1]的向量
消费者最终尺寸:0
--------------------------------------------------------------------------------
另一个_消费者(b,x)——这一个按预期工作
另一个_消费者初始大小:0
B.func START:vector_of_int[]
B.func-STOP:int[-1]的向量
另一个_消费者最终尺寸:1
x:int[-1]的向量

那么,我们在这里误解了什么?为什么第一个示例,即函数
consumer
,未能将std::vector的本地副本修改到位并通过引用从Python方法
B.func
返回?

下面的内容可能不太令人满意,但这是一个很容易的“欺骗”并让您继续,我想我还是发布它为好。正如上面的评论中所说,第二种情况是b/c工作的,python代理对象被发现已经存在,因此被重新使用。通过将蹦床代码更改为:

class PYB11TrampolineA: public A {
public:
  using A::A;
  virtual void func(std::vector<int>& vec) const override { 
    py::object dummy = py::cast(&vec);   // force re-use in the following call
    PYBIND11_OVERLOAD_PURE(void, A, func, vec); 
  }
};
在pybind11内部,它相当于相同的东西


EDIT2:找到了原因。在pybind11/2114.h的第2114行:使用
std::forward
删除了引用,其动机似乎是阻止创建python临时代理。最好通过引用对对象进行专门化。

第二种方法有效b/c对象标识保存找到现有的Python
x
,将其重新用于发送到b.func的绑定对象。我不明白的是,在第一种情况下,拷贝发生在哪里(你使用
PYBIND11\u MAKE\u不透明
应该可以防止这种情况)。你说得对——我确认在蹦床上添加py::cast可以让这个案例起作用。虽然最初的行为看起来像是无意的,但这实际上是pybind11错误吗?谢谢你的建议!也许是虫子;绝对不一致。。。在cppyy()中,我总是使用“C++类型+指针”作为对象标识,如果存在匹配,代理将被重新使用,因此我同意这一部分。但是,如果按值或拷贝(内部或从C++),那么就不会有优秀的C++指针,因此没有代理,CPPYY代码将不会搜索一个来重用。但是由于第二种解决方案(使用
&vec
)非常简单,可能它隐藏在文档的某个地方。。。(我个人找不到。)第二个解决方案非常简单,但这是一个棘手的细节,我一定要记住。如果这不是一个bug,那么在文档中肯定值得强调。你的回答会让我们重新开始,谢谢你的帮助!
class PYB11TrampolineA: public A {
public:
  using A::A;
  virtual void func(std::vector<int>& vec) const override { 
    py::object dummy = py::cast(&vec);   // force re-use in the following call
    PYBIND11_OVERLOAD_PURE(void, A, func, vec); 
  }
};
class PYB11TrampolineA: public A {
public:
  using A::A;
  virtual void func(std::vector<int>& vec) const override { 
    PYBIND11_OVERLOAD_PURE(void, A, func, &vec); 
  }
};