PyBind - Overloaded functions
Asked Answered
S

3

9

Firstly, my thanks to all of you for trying to resolve this doubt of mine. I am working on converting a minimal C++ project to be used in Python. The real reason behind this effort is for speed.

I came across PyBind and was quite surprised at its capabilities and also the amount of documentation they have provided. Right now there is something stopping the work because I have no idea on how to do it. Consider the below code in the file "MySource.hpp" and can you kindly tell me how a binding can be done?

    struct Point3D  
    {
    public:
        double x, y, z;
        CPoint3D();
        CPoint3D(double x, double y, double z); 
        inline double Len() const;
        inline void Normalize();
    };

    Point3D VectorCross(const Point3D& pt1, const Point3D& pt2, const Point3D& pt3);
    void VectorCross(const float* u, const float* v, float * n);

I was able to define a binding for Point3D as a class and certain of its member functions. But I don't have a clue about how to do the binding for the overloaded method "VectorCross". It has two methods with one accepting instances of Point3D, and another one accepting pointers to float arrays.

The binding I wrote so far is shown below

PYBIND11_MODULE(mymodule, m)
{
    py::class_<Point3D> point3d(m, "Point3D");
    point3d.def_readwrite("x", &CPoint3D::x);
    point3d.def_readwrite("y", &CPoint3D::y);
    point3d.def_readwrite("z", &CPoint3D::z);
    point3d.def(py::init<>());
    point3d.def(py::init<double , double , double >());
    point3d.def("Len", &CPoint3D::Len);
    point3d.def("Normalize", &CPoint3D::Normalize);
}

Can someone please guide me on how to do this?

Slosh answered 24/9, 2017 at 9:51 Comment(0)
N
16

It seems that you need to do overload cast as described here.

m.def("VectorCross", py::overload_cast<const Point3D&, const Point3D&, const Point3D&>(&VectorCross));
m.def("VectorCross", py::overload_cast<const float*, const float*, float*>(&VectorCross));
Nilsson answered 25/9, 2017 at 11:37 Comment(0)
S
0

Roman,

I figured this out but still selecting your answer as the right one for it really is the answer. But still in the case of method signature where it expects the arguments to be float pointers (below line)

m.def("VectorCross", py::overload_cast<const float*, const float*, float*>(&VectorCross));

compiles fine in creating a python library. But when you are try calling the method from python after importing the same will result in an argument error.

Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: AngleBetween(): incompatible function arguments. The following argument types are supported: 1. (pt1: chenhancc.CPoint3D, pt2: chenhancc.CPoint3D) -> float 2. (pt1: chenhancc.CPoint3D, pt2: chenhancc.CPoint3D, pt3: chenhancc.CPoint3D) -> float 3. (u: float, v: float) -> float

Looks like the python looks at it as if they are plain float number arguments.

But still my sincere thanks and appreciate your time.

Regards,

0K

Slosh answered 26/9, 2017 at 6:6 Comment(3)
What is AngleBetween()? This function is not in your code example.Nilsson
Ooops its a similar signature to the one I asked for initially. When I was writing the comment it was over there on my terminal as I was testing the same library. Sorry to have confused you.Slosh
This does not look like an answer; it looks like a comment on another answer.Cruikshank
T
0

You didn't specify which C++ standard you use and it might be of help to others with the same problem, so for the sake of completeness, if you can't use the C++14 overload_cast<> solution, you can also use static_cast like this:

m.def("VectorCross", static_cast<Point3D (*)(const Point3D&, const Point3D&, const Point3D&)>(&VectorCross));
m.def("VectorCross", static_cast<void (*)(const float*, const float*, float*)>(&VectorCross));
Thailand answered 5/4, 2023 at 6:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.