Pybind11: Improve the readability + remove #ifdef

Created on 24 Mar 2020  路  2Comments  路  Source: pybind/pybind11

I wrote a single C++ method called myFunclocated inside MyClassclass.

This method receive one nlohmann::json as input parameter.

To use this method in the Python side I have to convert the input Python dict argument (pybind11::object) to a nlohmann::json C++ type.

Implementation 1

Here is how I did it initially in the C++ side.
Method declaration located inside MyClass.h:

#ifdef PYBIND
    void myFunc(pybind11::object& pyConfig) const;
#else
    void myFunc(nlohmann::json& config) const;
#endif

Method implementation located inside MyClass.cpp:

#ifdef PYBIND
void MyClass::myFunc(pybind11::object& pyConfig) const
#else
void MyClass::myFunc(nlohmann::json& config) const
#endif
{

#ifdef PYBIND
    // Convert Python type to C++ type:
    nlohmann::json config = pyConfig;
#endif

    // Here is my C++ code using the 'config' variable.
}

This code works good in both environments: C++ and Python!

Well, now I'm trying to re-write this working code to improve the readability of the C++ code.

So, I would like to remove the #ifdef in both MyClass.h and MyClass.cpp files.
My inspiration to do that is in this topic #2140 .

Implementation 2

I would like to have just a single method declaration and a single method implementation using nlohmann::json as input parameter:

New declaration: without #ifdef

void myFunc(nlohmann::json& config) const;

New implementation: without #ifdef

void MyClass::myFunc(nlohmann::json& config) const
{
     // Here is my C++ code using the 'config' variable.
}

Try to bind it using Pybind11:

.def("myFunc", 
            [](pybind11::object& pyConfig)
            {
                // Convert Python type to C++ type:
                nlohmann::json config = pyConfig;

                // Call my C++ method:
                &MyClass::myFunc(config)
            })

When I try to compile this new implementation, I got this error below:

error: call to non-static member function without an object argument

I already tried to replace the word &MyClass to this...or just call myFunc(config)...but I still receive compile time errors.

How can I do it?

Most helpful comment

What is the .def() on, here? Is it bindings for MyClass? If so, try:

py::class_<MyClass>(m, "MyClass")
.def("myFunc", 
            [](MyClass &self, pybind11::object& pyConfig)
            {
                // Convert Python type to C++ type:
                nlohmann::json config = pyConfig;

                // Call my C++ method:
                self.myFunc(config);
            })

But in that case, I would normally suggest this:

py::class_<MyClass>(m, "MyClass")
.def("myFunc", &MyClass::myFunc);

So I must be missing something.

All 2 comments

What is the .def() on, here? Is it bindings for MyClass? If so, try:

py::class_<MyClass>(m, "MyClass")
.def("myFunc", 
            [](MyClass &self, pybind11::object& pyConfig)
            {
                // Convert Python type to C++ type:
                nlohmann::json config = pyConfig;

                // Call my C++ method:
                self.myFunc(config);
            })

But in that case, I would normally suggest this:

py::class_<MyClass>(m, "MyClass")
.def("myFunc", &MyClass::myFunc);

So I must be missing something.

Thank you again @carlsonmark ! It worked well!
You are the best!

Was this page helpful?
0 / 5 - 0 ratings