c++pybind11

How to bind this C++ class and function with pybind11?


I'm try to binding a C++ library with pybind11. I have a class that generates the instance with which to call the main functions that I don't know how to bind.

/*!
 *  @/class      FOO_API 
 *  @/brief      Structure for API support
 */
class FOO_API {
public:
    /*!
     *  @fn         Instance
     *  @brief      Class instance constructor FOO_API
     *  @return     FOO_API*     Return an initialized FOO_API object
     */
    static FOO_API* instance(struct config1 conf1, struct config2 conf2);
    
    /*!
     *  @fn         Liberate
     *  @brief      Free memory
     */
    static void liberate();

private:
    /*!
     *  @fn         FOO_API()
     *  @brief      Create an empty object FOO_API
     */
    FOO_API();

    /*!
     *  @fn         FOO_API(const FOO_API& orig)
     *  @brief      Create object from another 
     *  @param orig { Param FOO_API }
     */
    FOO_API(const FOO_API& orig);

    /*!
     *  @fn         virtual ~FOO_API()
     *  @brief      Free memory
     */
    virtual ~FOO_API();
    
    static FOO_API* m_pInstance;
    
    static class FOO_API_Impl* m_pInstanceImpl;
};

In the wrapper file I put something like that:

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "FOO_API.h"

namespace py = pybind11;

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin";
    py::class_<config1>(m, "config1")
        .def(py::init<>())
        .def_readwrite("foo", &config1::foo)

    py::class_<config2>(m, "config2")
        .def(py::init<>())
        .def_readwrite("bar", &config2::bar)

    py::class_<FOO_API>(m, "FOO_API")
        .def(py::init<>())
    m.def("instance", &instance);

When I'm trying compile the wrapper I get this error:

error: ‘instance’ was not declared in this scope
m.def("instance", &instance);

How should I create the FOO_API class and how should I call the instance() function from wrapper c++ code? Thanks for your comments

UPDATE 1:

Changing the FOO_API class following Rahut's recommendation

    // Exposing FOO_API class and its static methods
    py::class_<FOO_API, std::unique_ptr<FOO_API, py::nodelete>>(m, "FOO_API")
    // Use py::init to expose the constructor, but the constructor is private
    // so we are not exposing it directly.
    .def_static("instance",
        static_cast<FOO_API* (*)(config1, config2)>(&FOO_API::instance),
        py::return_value_policy::reference)
    .def_static("liberate", &FOO_API::liberate);

And calling the bind function from python code like this

import example as wrapper
conf1 = wrapper.config1
conf2 = wrapper.config2
pointerFOO_API = wrapper.FOO_API.instance(conf1, conf2)

returned this error

Traceback (most recent call last):
  File "main.py", line 160, in <module>
    pointerFOO_API = wrapper.FOO_API.instance(conf1, conf2)
TypeError: instance(): incompatible function arguments. The following argument types are supported:
    1. (arg0: example.config1, arg1: example.config2) -> example.FOO_API

Invoked with: <class 'example.config1'>, <class 'example.config2'>

Solution

  • #include <pybind11/pybind11.h>
    #include <pybind11/stl.h>
    #include "FOO_API.h"
    
    namespace py = pybind11;
    
    PYBIND11_MODULE(example, m) {
        m.doc() = "pybind11 example plugin";
    
        py::class_<config1>(m, "config1")
            .def(py::init<>())
            .def_readwrite("foo", &config1::foo);
    
        py::class_<config2>(m, "config2")
            .def(py::init<>())
            .def_readwrite("bar", &config2::bar);
    
         // Exposing FOO_API class and its static methods
        py::class_<FOO_API>(m, "FOO_API")
            // Use py::init to expose the constructor, but the constructor is private
            // so we are not exposing it directly.
            .def_static("instance",
                static_cast<FOO_API* (*)(config1, config2)>(&FOO_API::instance),
                py::arg("conf1"), py::arg("conf2"),
                py::return_value_policy::reference)
            .def_static("liberate", &FOO_API::liberate);
    }
    

    main.py to test it:

    import example as wrapper
    
    # Create instances of config1 and config2
    conf1 = wrapper.config1()  # Instantiate config1
    conf2 = wrapper.config2()  # Instantiate config2
    
    # Pass the instances to the FOO_API.instance() method
    pointerFOO_API = wrapper.FOO_API.instance(conf1, conf2)
    
    # Now you can use pointerFOO_API