From dcba6c6fa9d970d88f41036d361e9c39a623b95e Mon Sep 17 00:00:00 2001
From: Sebastiaan van der Tol <tol@astron.nl>
Date: Mon, 2 May 2022 12:13:32 +0200
Subject: [PATCH] Add pybind11 module using std::unique_ptr argument

---
 .gitmodules       |  3 ++
 CMakeLists.txt    | 12 +++++++
 external/pybind11 |  1 +
 mymodule.cc       | 82 +++++++++++++++++++++++++++++++++++++++++++++++
 testmymodule.py   | 18 +++++++++++
 5 files changed, 116 insertions(+)
 create mode 100644 .gitmodules
 create mode 100644 CMakeLists.txt
 create mode 160000 external/pybind11
 create mode 100644 mymodule.cc
 create mode 100755 testmymodule.py

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..7676f39
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "external/pybind11"]
+	path = external/pybind11
+	url = https://github.com/pybind/pybind11.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..ae071c5
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.8)
+
+project(pybind11-std-unique-ptr)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED YES)
+
+add_subdirectory("${CMAKE_SOURCE_DIR}/external/pybind11")
+
+pybind11_add_module(mymodule mymodule.cc)
+
+#include_directories(${pybind11_INCLUDE_DIRS})
\ No newline at end of file
diff --git a/external/pybind11 b/external/pybind11
new file mode 160000
index 0000000..75007dd
--- /dev/null
+++ b/external/pybind11
@@ -0,0 +1 @@
+Subproject commit 75007dda72ad4508064c1f080394eae50d3a61ee
diff --git a/mymodule.cc b/mymodule.cc
new file mode 100644
index 0000000..8a1e185
--- /dev/null
+++ b/mymodule.cc
@@ -0,0 +1,82 @@
+#include <iostream>
+#include <string>
+
+#include <pybind11/pybind11.h>
+
+namespace py = pybind11;
+
+// template<typename T> std::unique_ptr<T> py_unique_ptr(T &object) {
+//     py::object py_object(pybind11::cast(&object));
+//     return std::unique_ptr<T>(&object, [](T* p){});
+// }
+
+class Pet {
+  public:
+
+    Pet(const std::string &name) :
+    name_(name)
+    {
+      std::cout << "A pet named " << name_ << " came to life." << std::endl;
+    }
+
+    // Option 1 - no move constructor - moving will make a copy
+    // 
+    // Pet(Pet &&other)=delete;
+
+    // Option 2 - default move constructor - members will be moved into new object
+    // Pet(Pet &&other)=default;
+
+    // Option 3 - Custom move constructor
+    Pet(Pet &&other) :
+      name_((std::move(other.name_)))
+    {
+      std::cout << "Moving " << name_ << " to new pet." << std::endl;
+    }
+
+    virtual ~Pet()
+    {
+      std::cout << "A pet named '" << name_ << "' died." << std::endl;
+    }
+
+    std::string GetName() {return name_;}
+
+  private:
+    std::string name_;
+};
+
+class PetHolder {
+  public:
+    PetHolder(std::unique_ptr<Pet> pet) :
+      pet_(std::move(pet))
+    {}
+
+    std::string GetPetName() const {
+        return pet_->GetName();
+    }
+
+    void SetPet(std::unique_ptr<Pet> pet) {
+        pet_ = std::move(pet);
+    }
+  private:
+    std::unique_ptr<Pet> pet_;
+
+};
+
+class PyPetHolder : public PetHolder {
+  public:
+    PyPetHolder(Pet &pet) : PetHolder(std::make_unique<Pet>(std::move(pet)))
+    {}
+};
+
+PYBIND11_MODULE(mymodule, m) {
+  m.doc() = R"pbdoc(
+   module to demonstrate handling of std::unique_ptr arguments in pybind11.
+  )pbdoc";
+
+  py::class_<Pet>(m, "Pet")
+    .def(py::init<const std::string &>());
+    
+  py::class_<PyPetHolder>(m, "PetHolder")
+    .def(py::init<Pet&>());
+
+}
diff --git a/testmymodule.py b/testmymodule.py
new file mode 100755
index 0000000..918aa11
--- /dev/null
+++ b/testmymodule.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python3
+
+# Output:
+
+# A pet named Tweety came to life.
+# Moving Tweety to new pet.
+# A pet named '' died.
+# A pet named 'Tweety' died.
+
+import mymodule
+
+t = mymodule.Pet("Tweety")
+
+h = mymodule.PetHolder(t)
+
+del t
+del h
+
-- 
GitLab