Methods are not falling through to base class
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 18k
- Forks
- 2.3k
- Avg merge
- 5d 17h
- Merged PRs (30d)
- 10
Description
I have a problem with cases where some operators are associated with a base class and some with a derived class. If a derived class has an operator defined for a particular type, and for other types the operator is associated with the base class, the code does not drop down into the base class to find a suitable operator.
The below code illustrates the issue (tested with pybind11 master):
#include <pybind11/pybind11.h>
namespace py = pybind11;
class VectorBase
{
public:
virtual VectorBase& operator*=(const VectorBase& v) = 0;
virtual VectorBase& operator*=(float a) = 0;
virtual double operator[](int i) const = 0;
};
class Vector2 : public VectorBase
{
public:
Vector2(float x, float y) : x(x), y(y) { }
Vector2& operator*=(const VectorBase& v) { x *= v[0]; y *= v.[1]; return *this; }
Vector2& operator*=(float a) { x *= a; y *= a; return *this; }
double operator[] (int i) const {if (i==0) return x; return y;}
private:
float x, y;
};
PYBIND11_MODULE(cpp, m)
{
py::class_<VectorBase>(m, "VectorBase")
.def("__imul__", (VectorBase& (VectorBase::*)(float)) &VectorBase::operator*=)
.def("__imul__", (VectorBase& (VectorBase::*)(const VectorBase&)) &VectorBase::operator*=);
py::class_<Vector2, VectorBase>(m, "Vector2")
.def(py::init<float, float>())
// Remove the below definition and the code behaves as expected
.def("__imul__", [](Vector2& self, const VectorBase& v)
{
// Do something special here for Vector2 rather than going via
// the base class
return self;
}, py::arg().noconvert());
}
Running
import cpp
x = cpp.Vector2(1, 2)
x *= 2.0
I get the error
Traceback (most recent call last):
File "test.py", line 3, in <module>
x *= 2.0
TypeError: __imul__(): incompatible function arguments. The following argument types are supported:
1. (self: cpp.Vector2, arg0: cpp.VectorBase) -> cpp.Vector2
Invoked with: <cpp.Vector2 object at 0x109d9cd88>, 2.0
Removing the operator attached to Vector2 and the program behaves as expected.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the minimal C++/Python reproduction in the issue and trace pybind11's operator overload dispatch for inherited methods. Done when a Vector2-specific imul overload can coexist with the inherited VectorBase overload and x *= 2.0 resolves successfully, while the specialized Vector2 case still works.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, python
- Domain
- api
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100