Skip to content

Commit 152bdcc

Browse files
committed
new test style - test_virtual_functions (updates)
This adds a few missing `// test_whatever` comments, and moves the inherited virtual example code to the end, after the main set of tests (the latter also gets renamed to `test_inherited_virtuals` from `test_inheriting_repeat` because it tests both inherited virtual approaches, not just the repeat approach).
1 parent 2e5787c commit 152bdcc

File tree

2 files changed

+228
-228
lines changed

2 files changed

+228
-228
lines changed

tests/test_virtual_functions.cpp

Lines changed: 142 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,147 @@ class NCVirtTrampoline : public NCVirt {
145145
}
146146
};
147147

148-
int runExampleVirt(ExampleVirt *ex, int value) {
149-
return ex->run(value);
150-
}
148+
struct Base {
149+
/* for some reason MSVC2015 can't compile this if the function is pure virtual */
150+
virtual std::string dispatch() const { return {}; };
151+
};
151152

152-
bool runExampleVirtBool(ExampleVirt* ex) {
153-
return ex->run_bool();
154-
}
153+
struct DispatchIssue : Base {
154+
virtual std::string dispatch() const {
155+
PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
156+
}
157+
};
158+
159+
// Forward declaration (so that we can put the main tests here; the inherited virtual approaches are
160+
// rather long).
161+
void initialize_inherited_virtuals(py::module &m);
162+
163+
TEST_SUBMODULE(virtual_functions, m) {
164+
// test_override
165+
py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt")
166+
.def(py::init<int>())
167+
/* Reference original class in function definitions */
168+
.def("run", &ExampleVirt::run)
169+
.def("run_bool", &ExampleVirt::run_bool)
170+
.def("pure_virtual", &ExampleVirt::pure_virtual);
171+
172+
py::class_<NonCopyable>(m, "NonCopyable")
173+
.def(py::init<int, int>());
174+
175+
py::class_<Movable>(m, "Movable")
176+
.def(py::init<int, int>());
177+
178+
// test_move_support
179+
#if !defined(__INTEL_COMPILER)
180+
py::class_<NCVirt, NCVirtTrampoline>(m, "NCVirt")
181+
.def(py::init<>())
182+
.def("get_noncopyable", &NCVirt::get_noncopyable)
183+
.def("get_movable", &NCVirt::get_movable)
184+
.def("print_nc", &NCVirt::print_nc)
185+
.def("print_movable", &NCVirt::print_movable);
186+
#endif
187+
188+
m.def("runExampleVirt", [](ExampleVirt *ex, int value) { return ex->run(value); });
189+
m.def("runExampleVirtBool", [](ExampleVirt* ex) { return ex->run_bool(); });
190+
m.def("runExampleVirtVirtual", [](ExampleVirt *ex) { ex->pure_virtual(); });
191+
192+
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
193+
initialize_inherited_virtuals(m);
194+
195+
// test_alias_delay_initialization1
196+
// don't invoke Python dispatch classes by default when instantiating C++ classes
197+
// that were not extended on the Python side
198+
struct A {
199+
virtual ~A() {}
200+
virtual void f() { py::print("A.f()"); }
201+
};
202+
203+
struct PyA : A {
204+
PyA() { py::print("PyA.PyA()"); }
205+
~PyA() { py::print("PyA.~PyA()"); }
206+
207+
void f() override {
208+
py::print("PyA.f()");
209+
PYBIND11_OVERLOAD(void, A, f);
210+
}
211+
};
212+
213+
py::class_<A, PyA>(m, "A")
214+
.def(py::init<>())
215+
.def("f", &A::f);
216+
217+
m.def("call_f", [](A *a) { a->f(); });
218+
219+
// test_alias_delay_initialization2
220+
// ... unless we explicitly request it, as in this example:
221+
struct A2 {
222+
virtual ~A2() {}
223+
virtual void f() { py::print("A2.f()"); }
224+
};
225+
226+
struct PyA2 : A2 {
227+
PyA2() { py::print("PyA2.PyA2()"); }
228+
~PyA2() { py::print("PyA2.~PyA2()"); }
229+
void f() override {
230+
py::print("PyA2.f()");
231+
PYBIND11_OVERLOAD(void, A2, f);
232+
}
233+
};
234+
235+
py::class_<A2, PyA2>(m, "A2")
236+
.def(py::init_alias<>())
237+
.def("f", &A2::f);
238+
239+
m.def("call_f", [](A2 *a2) { a2->f(); });
240+
241+
// test_dispatch_issue
242+
// #159: virtual function dispatch has problems with similar-named functions
243+
py::class_<Base, DispatchIssue>(m, "DispatchIssue")
244+
.def(py::init<>())
245+
.def("dispatch", &Base::dispatch);
246+
247+
m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
248+
249+
// test_override_ref
250+
// #392/397: overridding reference-returning functions
251+
class OverrideTest {
252+
public:
253+
struct A { std::string value = "hi"; };
254+
std::string v;
255+
A a;
256+
explicit OverrideTest(const std::string &v) : v{v} {}
257+
virtual std::string str_value() { return v; }
258+
virtual std::string &str_ref() { return v; }
259+
virtual A A_value() { return a; }
260+
virtual A &A_ref() { return a; }
261+
};
155262

156-
void runExampleVirtVirtual(ExampleVirt *ex) {
157-
ex->pure_virtual();
263+
class PyOverrideTest : public OverrideTest {
264+
public:
265+
using OverrideTest::OverrideTest;
266+
std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
267+
// Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
268+
// to a python numeric value, since we only copy values in the numeric type caster:
269+
// std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); }
270+
// But we can work around it like this:
271+
private:
272+
std::string _tmp;
273+
std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); }
274+
public:
275+
std::string &str_ref() override { return _tmp = str_ref_helper(); }
276+
277+
A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); }
278+
A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); }
279+
};
280+
281+
py::class_<OverrideTest::A>(m, "OverrideTest_A")
282+
.def_readwrite("value", &OverrideTest::A::value);
283+
py::class_<OverrideTest, PyOverrideTest>(m, "OverrideTest")
284+
.def(py::init<const std::string &>())
285+
.def("str_value", &OverrideTest::str_value)
286+
// .def("str_ref", &OverrideTest::str_ref)
287+
.def("A_value", &OverrideTest::A_value)
288+
.def("A_ref", &OverrideTest::A_ref);
158289
}
159290

160291

@@ -281,6 +412,8 @@ template <class Base = D_Tpl> class PyD_Tpl : public PyC_Tpl<Base> {
281412

282413

283414
void initialize_inherited_virtuals(py::module &m) {
415+
// test_inherited_virtuals
416+
284417
// Method 1: repeat
285418
py::class_<A_Repeat, PyA_Repeat>(m, "A_Repeat")
286419
.def(py::init<>())
@@ -295,6 +428,7 @@ void initialize_inherited_virtuals(py::module &m) {
295428
py::class_<D_Repeat, C_Repeat, PyD_Repeat>(m, "D_Repeat")
296429
.def(py::init<>());
297430

431+
// test_
298432
// Method 2: Templated trampolines
299433
py::class_<A_Tpl, PyA_Tpl<>>(m, "A_Tpl")
300434
.def(py::init<>())
@@ -311,137 +445,3 @@ void initialize_inherited_virtuals(py::module &m) {
311445

312446
};
313447

314-
struct Base {
315-
/* for some reason MSVC2015 can't compile this if the function is pure virtual */
316-
virtual std::string dispatch() const { return {}; };
317-
};
318-
319-
struct DispatchIssue : Base {
320-
virtual std::string dispatch() const {
321-
PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
322-
}
323-
};
324-
325-
TEST_SUBMODULE(virtual_functions, m) {
326-
py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt")
327-
.def(py::init<int>())
328-
/* Reference original class in function definitions */
329-
.def("run", &ExampleVirt::run)
330-
.def("run_bool", &ExampleVirt::run_bool)
331-
.def("pure_virtual", &ExampleVirt::pure_virtual);
332-
333-
py::class_<NonCopyable>(m, "NonCopyable")
334-
.def(py::init<int, int>());
335-
336-
py::class_<Movable>(m, "Movable")
337-
.def(py::init<int, int>());
338-
339-
#if !defined(__INTEL_COMPILER)
340-
py::class_<NCVirt, NCVirtTrampoline>(m, "NCVirt")
341-
.def(py::init<>())
342-
.def("get_noncopyable", &NCVirt::get_noncopyable)
343-
.def("get_movable", &NCVirt::get_movable)
344-
.def("print_nc", &NCVirt::print_nc)
345-
.def("print_movable", &NCVirt::print_movable);
346-
#endif
347-
348-
m.def("runExampleVirt", &runExampleVirt);
349-
m.def("runExampleVirtBool", &runExampleVirtBool);
350-
m.def("runExampleVirtVirtual", &runExampleVirtVirtual);
351-
352-
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
353-
initialize_inherited_virtuals(m);
354-
355-
// test_alias_delay_initialization1
356-
// don't invoke Python dispatch classes by default when instantiating C++ classes
357-
// that were not extended on the Python side
358-
struct A {
359-
virtual ~A() {}
360-
virtual void f() { py::print("A.f()"); }
361-
};
362-
363-
struct PyA : A {
364-
PyA() { py::print("PyA.PyA()"); }
365-
~PyA() { py::print("PyA.~PyA()"); }
366-
367-
void f() override {
368-
py::print("PyA.f()");
369-
PYBIND11_OVERLOAD(void, A, f);
370-
}
371-
};
372-
373-
py::class_<A, PyA>(m, "A")
374-
.def(py::init<>())
375-
.def("f", &A::f);
376-
377-
m.def("call_f", [](A *a) { a->f(); });
378-
379-
// test_alias_delay_initialization2
380-
// ... unless we explicitly request it, as in this example:
381-
struct A2 {
382-
virtual ~A2() {}
383-
virtual void f() { py::print("A2.f()"); }
384-
};
385-
386-
struct PyA2 : A2 {
387-
PyA2() { py::print("PyA2.PyA2()"); }
388-
~PyA2() { py::print("PyA2.~PyA2()"); }
389-
void f() override {
390-
py::print("PyA2.f()");
391-
PYBIND11_OVERLOAD(void, A2, f);
392-
}
393-
};
394-
395-
py::class_<A2, PyA2>(m, "A2")
396-
.def(py::init_alias<>())
397-
.def("f", &A2::f);
398-
399-
m.def("call_f", [](A2 *a2) { a2->f(); });
400-
401-
// #159: virtual function dispatch has problems with similar-named functions
402-
py::class_<Base, DispatchIssue>(m, "DispatchIssue")
403-
.def(py::init<>())
404-
.def("dispatch", &Base::dispatch);
405-
406-
m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
407-
408-
// #392/397: overridding reference-returning functions
409-
class OverrideTest {
410-
public:
411-
struct A { std::string value = "hi"; };
412-
std::string v;
413-
A a;
414-
explicit OverrideTest(const std::string &v) : v{v} {}
415-
virtual std::string str_value() { return v; }
416-
virtual std::string &str_ref() { return v; }
417-
virtual A A_value() { return a; }
418-
virtual A &A_ref() { return a; }
419-
};
420-
421-
class PyOverrideTest : public OverrideTest {
422-
public:
423-
using OverrideTest::OverrideTest;
424-
std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
425-
// Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
426-
// to a python numeric value, since we only copy values in the numeric type caster:
427-
// std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); }
428-
// But we can work around it like this:
429-
private:
430-
std::string _tmp;
431-
std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); }
432-
public:
433-
std::string &str_ref() override { return _tmp = str_ref_helper(); }
434-
435-
A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); }
436-
A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); }
437-
};
438-
439-
py::class_<OverrideTest::A>(m, "OverrideTest_A")
440-
.def_readwrite("value", &OverrideTest::A::value);
441-
py::class_<OverrideTest, PyOverrideTest>(m, "OverrideTest")
442-
.def(py::init<const std::string &>())
443-
.def("str_value", &OverrideTest::str_value)
444-
// .def("str_ref", &OverrideTest::str_ref)
445-
.def("A_value", &OverrideTest::A_value)
446-
.def("A_ref", &OverrideTest::A_ref);
447-
}

0 commit comments

Comments
 (0)