mirror of
				https://github.com/PaddlePaddle/FastDeploy.git
				synced 2025-10-31 20:02:53 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			593 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			593 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|     tests/test_virtual_functions.cpp -- overriding virtual functions from Python
 | |
| 
 | |
|     Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
 | |
| 
 | |
|     All rights reserved. Use of this source code is governed by a
 | |
|     BSD-style license that can be found in the LICENSE file.
 | |
| */
 | |
| 
 | |
| #include <pybind11/functional.h>
 | |
| 
 | |
| #include "constructor_stats.h"
 | |
| #include "pybind11_tests.h"
 | |
| 
 | |
| #include <thread>
 | |
| 
 | |
| /* This is an example class that we'll want to be able to extend from Python */
 | |
| class ExampleVirt {
 | |
| public:
 | |
|     explicit ExampleVirt(int state) : state(state) { print_created(this, state); }
 | |
|     ExampleVirt(const ExampleVirt &e) : state(e.state) { print_copy_created(this); }
 | |
|     ExampleVirt(ExampleVirt &&e) noexcept : state(e.state) {
 | |
|         print_move_created(this);
 | |
|         e.state = 0;
 | |
|     }
 | |
|     virtual ~ExampleVirt() { print_destroyed(this); }
 | |
| 
 | |
|     virtual int run(int value) {
 | |
|         py::print("Original implementation of "
 | |
|                   "ExampleVirt::run(state={}, value={}, str1={}, str2={})"_s.format(
 | |
|                       state, value, get_string1(), *get_string2()));
 | |
|         return state + value;
 | |
|     }
 | |
| 
 | |
|     virtual bool run_bool() = 0;
 | |
|     virtual void pure_virtual() = 0;
 | |
| 
 | |
|     // Returning a reference/pointer to a type converted from python (numbers, strings, etc.) is a
 | |
|     // bit trickier, because the actual int& or std::string& or whatever only exists temporarily,
 | |
|     // so we have to handle it specially in the trampoline class (see below).
 | |
|     virtual const std::string &get_string1() { return str1; }
 | |
|     virtual const std::string *get_string2() { return &str2; }
 | |
| 
 | |
| private:
 | |
|     int state;
 | |
|     const std::string str1{"default1"}, str2{"default2"};
 | |
| };
 | |
| 
 | |
| /* This is a wrapper class that must be generated */
 | |
| class PyExampleVirt : public ExampleVirt {
 | |
| public:
 | |
|     using ExampleVirt::ExampleVirt; /* Inherit constructors */
 | |
| 
 | |
|     int run(int value) override {
 | |
|         /* Generate wrapping code that enables native function overloading */
 | |
|         PYBIND11_OVERRIDE(int,         /* Return type */
 | |
|                           ExampleVirt, /* Parent class */
 | |
|                           run,         /* Name of function */
 | |
|                           value        /* Argument(s) */
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     bool run_bool() override {
 | |
|         PYBIND11_OVERRIDE_PURE(bool,        /* Return type */
 | |
|                                ExampleVirt, /* Parent class */
 | |
|                                run_bool,    /* Name of function */
 | |
|                                             /* This function has no arguments. The trailing comma
 | |
|                                                in the previous line is needed for some compilers */
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     void pure_virtual() override {
 | |
|         PYBIND11_OVERRIDE_PURE(void,         /* Return type */
 | |
|                                ExampleVirt,  /* Parent class */
 | |
|                                pure_virtual, /* Name of function */
 | |
|                                              /* This function has no arguments. The trailing comma
 | |
|                                                 in the previous line is needed for some compilers */
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     // We can return reference types for compatibility with C++ virtual interfaces that do so, but
 | |
|     // note they have some significant limitations (see the documentation).
 | |
|     const std::string &get_string1() override {
 | |
|         PYBIND11_OVERRIDE(const std::string &, /* Return type */
 | |
|                           ExampleVirt,         /* Parent class */
 | |
|                           get_string1,         /* Name of function */
 | |
|                                                /* (no arguments) */
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     const std::string *get_string2() override {
 | |
|         PYBIND11_OVERRIDE(const std::string *, /* Return type */
 | |
|                           ExampleVirt,         /* Parent class */
 | |
|                           get_string2,         /* Name of function */
 | |
|                                                /* (no arguments) */
 | |
|         );
 | |
|     }
 | |
| };
 | |
| 
 | |
| class NonCopyable {
 | |
| public:
 | |
|     NonCopyable(int a, int b) : value{new int(a * b)} { print_created(this, a, b); }
 | |
|     NonCopyable(NonCopyable &&o) noexcept : value{std::move(o.value)} { print_move_created(this); }
 | |
|     NonCopyable(const NonCopyable &) = delete;
 | |
|     NonCopyable() = delete;
 | |
|     void operator=(const NonCopyable &) = delete;
 | |
|     void operator=(NonCopyable &&) = delete;
 | |
|     std::string get_value() const {
 | |
|         if (value) {
 | |
|             return std::to_string(*value);
 | |
|         }
 | |
|         return "(null)";
 | |
|     }
 | |
|     ~NonCopyable() { print_destroyed(this); }
 | |
| 
 | |
| private:
 | |
|     std::unique_ptr<int> value;
 | |
| };
 | |
| 
 | |
| // This is like the above, but is both copy and movable.  In effect this means it should get moved
 | |
| // when it is not referenced elsewhere, but copied if it is still referenced.
 | |
| class Movable {
 | |
| public:
 | |
|     Movable(int a, int b) : value{a + b} { print_created(this, a, b); }
 | |
|     Movable(const Movable &m) : value{m.value} { print_copy_created(this); }
 | |
|     Movable(Movable &&m) noexcept : value{m.value} { print_move_created(this); }
 | |
|     std::string get_value() const { return std::to_string(value); }
 | |
|     ~Movable() { print_destroyed(this); }
 | |
| 
 | |
| private:
 | |
|     int value;
 | |
| };
 | |
| 
 | |
| class NCVirt {
 | |
| public:
 | |
|     virtual ~NCVirt() = default;
 | |
|     NCVirt() = default;
 | |
|     NCVirt(const NCVirt &) = delete;
 | |
|     virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); }
 | |
|     virtual Movable get_movable(int a, int b) = 0;
 | |
| 
 | |
|     std::string print_nc(int a, int b) { return get_noncopyable(a, b).get_value(); }
 | |
|     std::string print_movable(int a, int b) { return get_movable(a, b).get_value(); }
 | |
| };
 | |
| class NCVirtTrampoline : public NCVirt {
 | |
| #if !defined(__INTEL_COMPILER) && !defined(__CUDACC__) && !defined(__PGIC__)
 | |
|     NonCopyable get_noncopyable(int a, int b) override {
 | |
|         PYBIND11_OVERRIDE(NonCopyable, NCVirt, get_noncopyable, a, b);
 | |
|     }
 | |
| #endif
 | |
|     Movable get_movable(int a, int b) override {
 | |
|         PYBIND11_OVERRIDE_PURE(Movable, NCVirt, get_movable, a, b);
 | |
|     }
 | |
| };
 | |
| 
 | |
| struct Base {
 | |
|     virtual std::string dispatch() const = 0;
 | |
|     virtual ~Base() = default;
 | |
|     Base() = default;
 | |
|     Base(const Base &) = delete;
 | |
| };
 | |
| 
 | |
| struct DispatchIssue : Base {
 | |
|     std::string dispatch() const override {
 | |
|         PYBIND11_OVERRIDE_PURE(std::string, Base, dispatch, /* no arguments */);
 | |
|     }
 | |
| };
 | |
| 
 | |
| // 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;
 | |
|         py::print("1st lock acquired");
 | |
|     }
 | |
| 
 | |
|     {
 | |
|         py::gil_scoped_acquire lock;
 | |
|         py::print("2nd lock acquired");
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void test_gil_from_thread() {
 | |
|     py::gil_scoped_release release;
 | |
| 
 | |
|     std::thread t(test_gil);
 | |
|     t.join();
 | |
| }
 | |
| 
 | |
| class test_override_cache_helper {
 | |
| 
 | |
| public:
 | |
|     virtual int func() { return 0; }
 | |
| 
 | |
|     test_override_cache_helper() = default;
 | |
|     virtual ~test_override_cache_helper() = default;
 | |
|     // Non-copyable
 | |
|     test_override_cache_helper &operator=(test_override_cache_helper const &Right) = delete;
 | |
|     test_override_cache_helper(test_override_cache_helper const &Copy) = delete;
 | |
| };
 | |
| 
 | |
| class test_override_cache_helper_trampoline : public test_override_cache_helper {
 | |
|     int func() override { PYBIND11_OVERRIDE(int, test_override_cache_helper, func); }
 | |
| };
 | |
| 
 | |
| inline int test_override_cache(std::shared_ptr<test_override_cache_helper> const &instance) {
 | |
|     return instance->func();
 | |
| }
 | |
| 
 | |
| // Forward declaration (so that we can put the main tests here; the inherited virtual approaches
 | |
| // are rather long).
 | |
| void initialize_inherited_virtuals(py::module_ &m);
 | |
| 
 | |
| TEST_SUBMODULE(virtual_functions, m) {
 | |
|     // test_override
 | |
|     py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt")
 | |
|         .def(py::init<int>())
 | |
|         /* Reference original class in function definitions */
 | |
|         .def("run", &ExampleVirt::run)
 | |
|         .def("run_bool", &ExampleVirt::run_bool)
 | |
|         .def("pure_virtual", &ExampleVirt::pure_virtual);
 | |
| 
 | |
|     py::class_<NonCopyable>(m, "NonCopyable").def(py::init<int, int>());
 | |
| 
 | |
|     py::class_<Movable>(m, "Movable").def(py::init<int, int>());
 | |
| 
 | |
|     // test_move_support
 | |
| #if !defined(__INTEL_COMPILER) && !defined(__CUDACC__) && !defined(__PGIC__)
 | |
|     py::class_<NCVirt, NCVirtTrampoline>(m, "NCVirt")
 | |
|         .def(py::init<>())
 | |
|         .def("get_noncopyable", &NCVirt::get_noncopyable)
 | |
|         .def("get_movable", &NCVirt::get_movable)
 | |
|         .def("print_nc", &NCVirt::print_nc)
 | |
|         .def("print_movable", &NCVirt::print_movable);
 | |
| #endif
 | |
| 
 | |
|     m.def("runExampleVirt", [](ExampleVirt *ex, int value) { return ex->run(value); });
 | |
|     m.def("runExampleVirtBool", [](ExampleVirt *ex) { return ex->run_bool(); });
 | |
|     m.def("runExampleVirtVirtual", [](ExampleVirt *ex) { ex->pure_virtual(); });
 | |
| 
 | |
|     m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
 | |
|     initialize_inherited_virtuals(m);
 | |
| 
 | |
|     // test_alias_delay_initialization1
 | |
|     // don't invoke Python dispatch classes by default when instantiating C++ classes
 | |
|     // that were not extended on the Python side
 | |
|     struct A {
 | |
|         A() = default;
 | |
|         A(const A &) = delete;
 | |
|         virtual ~A() = default;
 | |
|         virtual void f() { py::print("A.f()"); }
 | |
|     };
 | |
| 
 | |
|     struct PyA : A {
 | |
|         PyA() { py::print("PyA.PyA()"); }
 | |
|         PyA(const PyA &) = delete;
 | |
|         ~PyA() override { py::print("PyA.~PyA()"); }
 | |
| 
 | |
|         void f() override {
 | |
|             py::print("PyA.f()");
 | |
|             // This convolution just gives a `void`, but tests that PYBIND11_TYPE() works to
 | |
|             // protect a type containing a ,
 | |
|             PYBIND11_OVERRIDE(PYBIND11_TYPE(typename std::enable_if<true, void>::type), A, f);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     py::class_<A, PyA>(m, "A").def(py::init<>()).def("f", &A::f);
 | |
| 
 | |
|     m.def("call_f", [](A *a) { a->f(); });
 | |
| 
 | |
|     // test_alias_delay_initialization2
 | |
|     // ... unless we explicitly request it, as in this example:
 | |
|     struct A2 {
 | |
|         A2() = default;
 | |
|         A2(const A2 &) = delete;
 | |
|         virtual ~A2() = default;
 | |
|         virtual void f() { py::print("A2.f()"); }
 | |
|     };
 | |
| 
 | |
|     struct PyA2 : A2 {
 | |
|         PyA2() { py::print("PyA2.PyA2()"); }
 | |
|         PyA2(const PyA2 &) = delete;
 | |
|         ~PyA2() override { py::print("PyA2.~PyA2()"); }
 | |
|         void f() override {
 | |
|             py::print("PyA2.f()");
 | |
|             PYBIND11_OVERRIDE(void, A2, f);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     py::class_<A2, PyA2>(m, "A2")
 | |
|         .def(py::init_alias<>())
 | |
|         .def(py::init([](int) { return new PyA2(); }))
 | |
|         .def("f", &A2::f);
 | |
| 
 | |
|     m.def("call_f", [](A2 *a2) { a2->f(); });
 | |
| 
 | |
|     // test_dispatch_issue
 | |
|     // #159: virtual function dispatch has problems with similar-named functions
 | |
|     py::class_<Base, DispatchIssue>(m, "DispatchIssue")
 | |
|         .def(py::init<>())
 | |
|         .def("dispatch", &Base::dispatch);
 | |
| 
 | |
|     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); // NOLINT(readability-suspicious-call-argument)
 | |
|               });
 | |
|           });
 | |
| 
 | |
|     // test_override_ref
 | |
|     // #392/397: overriding reference-returning functions
 | |
|     class OverrideTest {
 | |
|     public:
 | |
|         struct A {
 | |
|             std::string value = "hi";
 | |
|         };
 | |
|         std::string v;
 | |
|         A a;
 | |
|         explicit OverrideTest(const std::string &v) : v{v} {}
 | |
|         OverrideTest() = default;
 | |
|         OverrideTest(const OverrideTest &) = delete;
 | |
|         virtual std::string str_value() { return v; }
 | |
|         virtual std::string &str_ref() { return v; }
 | |
|         virtual A A_value() { return a; }
 | |
|         virtual A &A_ref() { return a; }
 | |
|         virtual ~OverrideTest() = default;
 | |
|     };
 | |
| 
 | |
|     class PyOverrideTest : public OverrideTest {
 | |
|     public:
 | |
|         using OverrideTest::OverrideTest;
 | |
|         std::string str_value() override {
 | |
|             PYBIND11_OVERRIDE(std::string, OverrideTest, str_value);
 | |
|         }
 | |
|         // Not allowed (enabling the below should hit a static_assert failure): we can't get a
 | |
|         // reference to a python numeric value, since we only copy values in the numeric type
 | |
|         // caster:
 | |
| #ifdef PYBIND11_NEVER_DEFINED_EVER
 | |
|         std::string &str_ref() override {
 | |
|             PYBIND11_OVERRIDE(std::string &, OverrideTest, str_ref);
 | |
|         }
 | |
| #endif
 | |
|         // But we can work around it like this:
 | |
|     private:
 | |
|         std::string _tmp;
 | |
|         std::string str_ref_helper() { PYBIND11_OVERRIDE(std::string, OverrideTest, str_ref); }
 | |
| 
 | |
|     public:
 | |
|         std::string &str_ref() override { return _tmp = str_ref_helper(); }
 | |
| 
 | |
|         A A_value() override { PYBIND11_OVERRIDE(A, OverrideTest, A_value); }
 | |
|         A &A_ref() override { PYBIND11_OVERRIDE(A &, OverrideTest, A_ref); }
 | |
|     };
 | |
| 
 | |
|     py::class_<OverrideTest::A>(m, "OverrideTest_A")
 | |
|         .def_readwrite("value", &OverrideTest::A::value);
 | |
|     py::class_<OverrideTest, PyOverrideTest>(m, "OverrideTest")
 | |
|         .def(py::init<const std::string &>())
 | |
|         .def("str_value", &OverrideTest::str_value)
 | |
| #ifdef PYBIND11_NEVER_DEFINED_EVER
 | |
|         .def("str_ref", &OverrideTest::str_ref)
 | |
| #endif
 | |
|         .def("A_value", &OverrideTest::A_value)
 | |
|         .def("A_ref", &OverrideTest::A_ref);
 | |
| 
 | |
|     py::class_<test_override_cache_helper,
 | |
|                test_override_cache_helper_trampoline,
 | |
|                std::shared_ptr<test_override_cache_helper>>(m, "test_override_cache_helper")
 | |
|         .def(py::init_alias<>())
 | |
|         .def("func", &test_override_cache_helper::func);
 | |
| 
 | |
|     m.def("test_override_cache", test_override_cache);
 | |
| }
 | |
| 
 | |
| // Inheriting virtual methods.  We do two versions here: the repeat-everything version and the
 | |
| // templated trampoline versions mentioned in docs/advanced.rst.
 | |
| //
 | |
| // These base classes are exactly the same, but we technically need distinct
 | |
| // classes for this example code because we need to be able to bind them
 | |
| // properly (pybind11, sensibly, doesn't allow us to bind the same C++ class to
 | |
| // multiple python classes).
 | |
| class A_Repeat {
 | |
| #define A_METHODS                                                                                 \
 | |
| public:                                                                                           \
 | |
|     virtual int unlucky_number() = 0;                                                             \
 | |
|     virtual std::string say_something(unsigned times) {                                           \
 | |
|         std::string s = "";                                                                       \
 | |
|         for (unsigned i = 0; i < times; ++i)                                                      \
 | |
|             s += "hi";                                                                            \
 | |
|         return s;                                                                                 \
 | |
|     }                                                                                             \
 | |
|     std::string say_everything() {                                                                \
 | |
|         return say_something(1) + " " + std::to_string(unlucky_number());                         \
 | |
|     }
 | |
|     A_METHODS
 | |
|     A_Repeat() = default;
 | |
|     A_Repeat(const A_Repeat &) = delete;
 | |
|     virtual ~A_Repeat() = default;
 | |
| };
 | |
| class B_Repeat : public A_Repeat {
 | |
| #define B_METHODS                                                                                 \
 | |
| public:                                                                                           \
 | |
|     int unlucky_number() override { return 13; }                                                  \
 | |
|     std::string say_something(unsigned times) override {                                          \
 | |
|         return "B says hi " + std::to_string(times) + " times";                                   \
 | |
|     }                                                                                             \
 | |
|     virtual double lucky_number() { return 7.0; }
 | |
|     B_METHODS
 | |
| };
 | |
| class C_Repeat : public B_Repeat {
 | |
| #define C_METHODS                                                                                 \
 | |
| public:                                                                                           \
 | |
|     int unlucky_number() override { return 4444; }                                                \
 | |
|     double lucky_number() override { return 888; }
 | |
|     C_METHODS
 | |
| };
 | |
| class D_Repeat : public C_Repeat {
 | |
| #define D_METHODS // Nothing overridden.
 | |
|     D_METHODS
 | |
| };
 | |
| 
 | |
| // Base classes for templated inheritance trampolines.  Identical to the repeat-everything version:
 | |
| class A_Tpl {
 | |
|     A_METHODS;
 | |
|     A_Tpl() = default;
 | |
|     A_Tpl(const A_Tpl &) = delete;
 | |
|     virtual ~A_Tpl() = default;
 | |
| };
 | |
| class B_Tpl : public A_Tpl {
 | |
|     B_METHODS
 | |
| };
 | |
| class C_Tpl : public B_Tpl {
 | |
|     C_METHODS
 | |
| };
 | |
| class D_Tpl : public C_Tpl {
 | |
|     D_METHODS
 | |
| };
 | |
| 
 | |
| // Inheritance approach 1: each trampoline gets every virtual method (11 in total)
 | |
| class PyA_Repeat : public A_Repeat {
 | |
| public:
 | |
|     using A_Repeat::A_Repeat;
 | |
|     int unlucky_number() override { PYBIND11_OVERRIDE_PURE(int, A_Repeat, unlucky_number, ); }
 | |
|     std::string say_something(unsigned times) override {
 | |
|         PYBIND11_OVERRIDE(std::string, A_Repeat, say_something, times);
 | |
|     }
 | |
| };
 | |
| class PyB_Repeat : public B_Repeat {
 | |
| public:
 | |
|     using B_Repeat::B_Repeat;
 | |
|     int unlucky_number() override { PYBIND11_OVERRIDE(int, B_Repeat, unlucky_number, ); }
 | |
|     std::string say_something(unsigned times) override {
 | |
|         PYBIND11_OVERRIDE(std::string, B_Repeat, say_something, times);
 | |
|     }
 | |
|     double lucky_number() override { PYBIND11_OVERRIDE(double, B_Repeat, lucky_number, ); }
 | |
| };
 | |
| class PyC_Repeat : public C_Repeat {
 | |
| public:
 | |
|     using C_Repeat::C_Repeat;
 | |
|     int unlucky_number() override { PYBIND11_OVERRIDE(int, C_Repeat, unlucky_number, ); }
 | |
|     std::string say_something(unsigned times) override {
 | |
|         PYBIND11_OVERRIDE(std::string, C_Repeat, say_something, times);
 | |
|     }
 | |
|     double lucky_number() override { PYBIND11_OVERRIDE(double, C_Repeat, lucky_number, ); }
 | |
| };
 | |
| class PyD_Repeat : public D_Repeat {
 | |
| public:
 | |
|     using D_Repeat::D_Repeat;
 | |
|     int unlucky_number() override { PYBIND11_OVERRIDE(int, D_Repeat, unlucky_number, ); }
 | |
|     std::string say_something(unsigned times) override {
 | |
|         PYBIND11_OVERRIDE(std::string, D_Repeat, say_something, times);
 | |
|     }
 | |
|     double lucky_number() override { PYBIND11_OVERRIDE(double, D_Repeat, lucky_number, ); }
 | |
| };
 | |
| 
 | |
| // Inheritance approach 2: templated trampoline classes.
 | |
| //
 | |
| // Advantages:
 | |
| // - we have only 2 (template) class and 4 method declarations (one per virtual method, plus one
 | |
| //   for any override of a pure virtual method), versus 4 classes and 6 methods (MI) or 4 classes
 | |
| //   and 11 methods (repeat).
 | |
| // - Compared to MI, we also don't have to change the non-trampoline inheritance to virtual, and
 | |
| //   can properly inherit constructors.
 | |
| //
 | |
| // Disadvantage:
 | |
| // - the compiler must still generate and compile 14 different methods (more, even, than the 11
 | |
| //   required for the repeat approach) instead of the 6 required for MI.  (If there was no pure
 | |
| //   method (or no pure method override), the number would drop down to the same 11 as the repeat
 | |
| //   approach).
 | |
| template <class Base = A_Tpl>
 | |
| class PyA_Tpl : public Base {
 | |
| public:
 | |
|     using Base::Base; // Inherit constructors
 | |
|     int unlucky_number() override { PYBIND11_OVERRIDE_PURE(int, Base, unlucky_number, ); }
 | |
|     std::string say_something(unsigned times) override {
 | |
|         PYBIND11_OVERRIDE(std::string, Base, say_something, times);
 | |
|     }
 | |
| };
 | |
| template <class Base = B_Tpl>
 | |
| class PyB_Tpl : public PyA_Tpl<Base> {
 | |
| public:
 | |
|     using PyA_Tpl<Base>::PyA_Tpl; // Inherit constructors (via PyA_Tpl's inherited constructors)
 | |
|     // NOLINTNEXTLINE(bugprone-parent-virtual-call)
 | |
|     int unlucky_number() override { PYBIND11_OVERRIDE(int, Base, unlucky_number, ); }
 | |
|     double lucky_number() override { PYBIND11_OVERRIDE(double, Base, lucky_number, ); }
 | |
| };
 | |
| // Since C_Tpl and D_Tpl don't declare any new virtual methods, we don't actually need these
 | |
| // (we can use PyB_Tpl<C_Tpl> and PyB_Tpl<D_Tpl> for the trampoline classes instead):
 | |
| /*
 | |
| template <class Base = C_Tpl> class PyC_Tpl : public PyB_Tpl<Base> {
 | |
| public:
 | |
|     using PyB_Tpl<Base>::PyB_Tpl;
 | |
| };
 | |
| template <class Base = D_Tpl> class PyD_Tpl : public PyC_Tpl<Base> {
 | |
| public:
 | |
|     using PyC_Tpl<Base>::PyC_Tpl;
 | |
| };
 | |
| */
 | |
| 
 | |
| void initialize_inherited_virtuals(py::module_ &m) {
 | |
|     // test_inherited_virtuals
 | |
| 
 | |
|     // Method 1: repeat
 | |
|     py::class_<A_Repeat, PyA_Repeat>(m, "A_Repeat")
 | |
|         .def(py::init<>())
 | |
|         .def("unlucky_number", &A_Repeat::unlucky_number)
 | |
|         .def("say_something", &A_Repeat::say_something)
 | |
|         .def("say_everything", &A_Repeat::say_everything);
 | |
|     py::class_<B_Repeat, A_Repeat, PyB_Repeat>(m, "B_Repeat")
 | |
|         .def(py::init<>())
 | |
|         .def("lucky_number", &B_Repeat::lucky_number);
 | |
|     py::class_<C_Repeat, B_Repeat, PyC_Repeat>(m, "C_Repeat").def(py::init<>());
 | |
|     py::class_<D_Repeat, C_Repeat, PyD_Repeat>(m, "D_Repeat").def(py::init<>());
 | |
| 
 | |
|     // test_
 | |
|     // Method 2: Templated trampolines
 | |
|     py::class_<A_Tpl, PyA_Tpl<>>(m, "A_Tpl")
 | |
|         .def(py::init<>())
 | |
|         .def("unlucky_number", &A_Tpl::unlucky_number)
 | |
|         .def("say_something", &A_Tpl::say_something)
 | |
|         .def("say_everything", &A_Tpl::say_everything);
 | |
|     py::class_<B_Tpl, A_Tpl, PyB_Tpl<>>(m, "B_Tpl")
 | |
|         .def(py::init<>())
 | |
|         .def("lucky_number", &B_Tpl::lucky_number);
 | |
|     py::class_<C_Tpl, B_Tpl, PyB_Tpl<C_Tpl>>(m, "C_Tpl").def(py::init<>());
 | |
|     py::class_<D_Tpl, C_Tpl, PyB_Tpl<D_Tpl>>(m, "D_Tpl").def(py::init<>());
 | |
| 
 | |
|     // Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
 | |
|     m.def("test_gil", &test_gil);
 | |
|     m.def("test_gil_from_thread", &test_gil_from_thread);
 | |
| };
 | 
