mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 06:35:12 +00:00
tests: test recursive dispatch using visitor pattern (#3365)
This commit is contained in:
parent
606f81a966
commit
076c89fc54
@ -174,6 +174,25 @@ struct DispatchIssue : Base {
|
||||
}
|
||||
};
|
||||
|
||||
// An abstract adder class that uses visitor pattern to add two data
|
||||
// objects and send the result to the visitor functor
|
||||
struct AdderBase {
|
||||
struct Data {};
|
||||
using DataVisitor = std::function<void (const Data&)>;
|
||||
|
||||
virtual void operator()(const Data& first, const Data& second, const DataVisitor& visitor) const = 0;
|
||||
virtual ~AdderBase() = default;
|
||||
AdderBase() = default;
|
||||
AdderBase(const AdderBase&) = delete;
|
||||
};
|
||||
|
||||
struct Adder : AdderBase {
|
||||
void operator()(const Data& first, const Data& second, const DataVisitor& visitor) const override {
|
||||
PYBIND11_OVERRIDE_PURE_NAME(void, AdderBase, "__call__", operator(), first, second, visitor);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void test_gil() {
|
||||
{
|
||||
py::gil_scoped_acquire lock;
|
||||
@ -295,6 +314,27 @@ TEST_SUBMODULE(virtual_functions, m) {
|
||||
|
||||
m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
|
||||
|
||||
// test_recursive_dispatch_issue
|
||||
// #3357: Recursive dispatch fails to find python function override
|
||||
pybind11::class_<AdderBase, Adder>(m, "Adder")
|
||||
.def(pybind11::init<>())
|
||||
.def("__call__", &AdderBase::operator());
|
||||
|
||||
pybind11::class_<AdderBase::Data>(m, "Data")
|
||||
.def(pybind11::init<>());
|
||||
|
||||
m.def("add2", [](const AdderBase::Data& first, const AdderBase::Data& second,
|
||||
const AdderBase& adder, const AdderBase::DataVisitor& visitor) {
|
||||
adder(first, second, visitor);
|
||||
});
|
||||
|
||||
m.def("add3", [](const AdderBase::Data& first, const AdderBase::Data& second, const AdderBase::Data& third,
|
||||
const AdderBase& adder, const AdderBase::DataVisitor& visitor) {
|
||||
adder(first, second, [&] (const AdderBase::Data& first_plus_second) {
|
||||
adder(first_plus_second, third, visitor);
|
||||
});
|
||||
});
|
||||
|
||||
// test_override_ref
|
||||
// #392/397: overriding reference-returning functions
|
||||
class OverrideTest {
|
||||
|
@ -257,6 +257,39 @@ def test_dispatch_issue(msg):
|
||||
assert m.dispatch_issue_go(b) == "Yay.."
|
||||
|
||||
|
||||
def test_recursive_dispatch_issue(msg):
|
||||
"""#3357: Recursive dispatch fails to find python function override"""
|
||||
|
||||
class Data(m.Data):
|
||||
def __init__(self, value):
|
||||
super(Data, self).__init__()
|
||||
self.value = value
|
||||
|
||||
class Adder(m.Adder):
|
||||
def __call__(self, first, second, visitor):
|
||||
# lambda is a workaround, which adds extra frame to the
|
||||
# current CPython thread. Removing lambda reveals the bug
|
||||
# [https://github.com/pybind/pybind11/issues/3357]
|
||||
(lambda: visitor(Data(first.value + second.value)))()
|
||||
|
||||
class StoreResultVisitor:
|
||||
def __init__(self):
|
||||
self.result = None
|
||||
|
||||
def __call__(self, data):
|
||||
self.result = data.value
|
||||
|
||||
store = StoreResultVisitor()
|
||||
|
||||
m.add2(Data(1), Data(2), Adder(), store)
|
||||
assert store.result == 3
|
||||
|
||||
# without lambda in Adder class, this function fails with
|
||||
# RuntimeError: Tried to call pure virtual function "AdderBase::__call__"
|
||||
m.add3(Data(1), Data(2), Data(3), Adder(), store)
|
||||
assert store.result == 6
|
||||
|
||||
|
||||
def test_override_ref():
|
||||
"""#392/397: overriding reference-returning functions"""
|
||||
o = m.OverrideTest("asdf")
|
||||
|
Loading…
Reference in New Issue
Block a user