Yes I know this answer is pretty late but the solutions provided before are either outdated or solve the Problem in a obscure way.
The biggest Problem with the other answers is that they use pybind and the raw Python interface at once. With pybind you can use a simpler and nicer interface to the Interpreter.
Following a implementation which should solve your Problem.
The first thing you will notice is that we use the "embed.h" Header file.
This gives us the Functions to create embedded Modules.
Further down we use the PYBIND11_EMBEDDED_MODULE
instead of the regular PYBIND11_MODULE
or the outdated PYBIND11_PLUGIN
. This is a Macro specifically for embedding.
The next interesting part are the types we define for our structure. Besides the Dog
Type we also use the shared_ptr<Dog>
. This is crucial for dealing with instances. When the main
module goes out of Scope and starts cleaning up it needs to know that the Class/Struct was of type shared_ptr otherwise you will get a seg fault (Raw Pointers are not usable here, I personally think this a good thing).
The last thing to point out is that we actually use the class pybind11::scoped_interpreter
for our interpreter and don't use the Raw Python interface.
#include"pybind11\pybind11.h"
#include"pybind11\embed.h"
#include<iostream>
namespace py = pybind11;
struct Dog {
void bark() { std::cout << "Bark!\n"; }
};
PYBIND11_EMBEDDED_MODULE(DogModule, m) {
// look at the types! we have a shared_ptr<Dog>!
py::class_<Dog, std::shared_ptr<Dog>>(m, "DogModule")
.def("bark", &Dog::bark);
}
int main(int argc, char **argv)
{
// Create Python Interpreter
py::scoped_interpreter guard;
// Create Dog Instance
std::shared_ptr<Dog> ptr = std::make_shared<Dog>();
// Import the DogModule & Assign the instance to a name in python
py::module main = py::module::import("__main__");
main.import("DogModule");
main.attr("dogInstance") = ptr;
// Call the bark method from python
py::exec("dogInstance.bark()");
getchar();
return 0;
}