如何在pybind11中将共享指针列表传递给c++对象

Posted

技术标签:

【中文标题】如何在pybind11中将共享指针列表传递给c++对象【英文标题】:How to pass list of shared pointers to c++ object in pybind11 【发布时间】:2019-11-16 12:18:47 【问题描述】:

我正在构建一个 ml 项目,它将使用 tensorflow、由 c++ 库和 python 播放器控制的游戏规则集。

我决定使用 pybind 作为游戏规则引擎和玩家控制层之间的转换层。

以下是我尝试用 pybind 封装的类:

class Player

public:
  Player() = default;
  virtual PlayerId getId() const = 0;
  virtual void playTurn(Turn&) = 0;
  virtual void takeHint(std::list<CardId>, Color) = 0;
  virtual void takeHint(std::list<CardId>, Value) = 0;
  virtual ~Player() = default;
;

using Players = std::list<std::shared_ptr<Player>>;

class Game

(...)
public:
  Game(const Game&) = delete;
  Game(Game&&) = delete;
  Game(const Players& players, const Cards&);
  void turn();
  int getScore() const;
;

这是我的包装方式:

PYBIND11_MODULE(hanabi_py, m)

  m.doc() = "hanabi-cpp wrapper for python";
  py::class_<Game>(m, "Game")
    .def(py::init<const Players&, const Cards&>())
    .def("turn", &Game::turn)
    .def("getScore", &Game::getScore);

  py::class_<Player, std::shared_ptr<Player>, PyPlayer>(m, "Player")
    .def(py::init<>())
    .def("getId", &Player::getId, "Get id")
    .def("playTurn", &Player::playTurn, "Play turn", py::arg("turn"))
    .def("takeHint",
         py::overload_cast<std::list<CardId>, Color>(&Player::takeHint),
         "take color hint")
    .def("takeHint",
         py::overload_cast<std::list<CardId>, Value>(&Player::takeHint),
         "take value hint");

(...)

完整代码见:https://github.com/morynicz/hanabi-cpp

尝试使用以下方式创建游戏时:

import hanabi_py as h

class PyPlayer(h.Player):
    def __init__(self, id):
        h.Player.__init__(self)
        self.id = id

    def getId(self):
        return self.id

    def playTurn(self,turn):
        pass

    def takeHint(self, ids, arg):
        pass

def attempt():
        p = PyPlayer(1)
        c = h.Card
        c.id = 0
        c.color = h.Color.Red
        c.value = h.Value.One
        g = h.Game([p],[c])

我明白了:

TypeError: init(): 不兼容的构造函数参数。支持以下参数类型: 1. hanabi_py.Game(arg0: List[Player], arg1: List[Card])

问题 如何将派生自C++类的python类的python对象包装到shared_ptr中,然后再放入列表中?

我知道我可以尝试添加一些函数来用 shared_ptr 包装 python 对象,但请记住,已经有 shared_ptr 持有者在使用这似乎是一个非常糟糕的主意。

编辑: 看来问题不在于shared_ptr,而在于列表。由于某种原因,它没有得到正确解决。我尝试为玩家制作一个不透明的类,但它不起作用

TypeError: init(): 不兼容的构造函数参数。支持以下参数类型: 1. hanabi_py.Game(玩家: std::__cxx11::list, std::allocator >>, 卡片: List[Card])

所以目前的问题是: 如何将 python 对象列表作为 std::list> 从 python 传递给 C++ 对象?

【问题讨论】:

【参考方案1】:

这一行:

c = h.Card

使c 成为Card 类型。你需要在py::class_&lt;Card&gt;(m, "Card")的构造中添加一个构造函数.def(py::init&lt;&gt;()),然后做c = h.Card()

【讨论】:

以上是关于如何在pybind11中将共享指针列表传递给c++对象的主要内容,如果未能解决你的问题,请参考以下文章

pybind11 返回 numpy 对象数组

从 python 传递到 C++ 的数组中未映射的内存访问

在 C++ 中将指向基类的指针传递给派生类的成员函数

管理 sharedPointers C++

Pybind - 使用指向派生类的共享指针调用函数

如何在 C++ 中将指针转换/转换为引用