1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
/*
tests/test_tagbased_polymorphic.cpp -- test of polymorphic_type_hook
Copyright (c) 2018 Hudson River Trading LLC <opensource@hudson-trading.com>
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_tests.h"
#include <pybind11/stl.h>
struct Animal
{
enum class Kind {
Unknown = 0,
Dog = 100, Labrador, Chihuahua, LastDog = 199,
Cat = 200, Panther, LastCat = 299
};
static const std::type_info* type_of_kind(Kind kind);
static std::string name_of_kind(Kind kind);
const Kind kind;
const std::string name;
protected:
Animal(const std::string& _name, Kind _kind)
: kind(_kind), name(_name)
{}
};
struct Dog : Animal
{
Dog(const std::string& _name, Kind _kind = Kind::Dog) : Animal(_name, _kind) {}
std::string bark() const { return name_of_kind(kind) + " " + name + " goes " + sound; }
std::string sound = "WOOF!";
};
struct Labrador : Dog
{
Labrador(const std::string& _name, int _excitement = 9001)
: Dog(_name, Kind::Labrador), excitement(_excitement) {}
int excitement;
};
struct Chihuahua : Dog
{
Chihuahua(const std::string& _name) : Dog(_name, Kind::Chihuahua) { sound = "iyiyiyiyiyi"; }
std::string bark() const { return Dog::bark() + " and runs in circles"; }
};
struct Cat : Animal
{
Cat(const std::string& _name, Kind _kind = Kind::Cat) : Animal(_name, _kind) {}
std::string purr() const { return "mrowr"; }
};
struct Panther : Cat
{
Panther(const std::string& _name) : Cat(_name, Kind::Panther) {}
std::string purr() const { return "mrrrRRRRRR"; }
};
std::vector<std::unique_ptr<Animal>> create_zoo()
{
std::vector<std::unique_ptr<Animal>> ret;
ret.emplace_back(new Labrador("Fido", 15000));
// simulate some new type of Dog that the Python bindings
// haven't been updated for; it should still be considered
// a Dog, not just an Animal.
ret.emplace_back(new Dog("Ginger", Dog::Kind(150)));
ret.emplace_back(new Chihuahua("Hertzl"));
ret.emplace_back(new Cat("Tiger", Cat::Kind::Cat));
ret.emplace_back(new Panther("Leo"));
return ret;
}
const std::type_info* Animal::type_of_kind(Kind kind)
{
switch (kind) {
case Kind::Unknown: break;
case Kind::Dog: break;
case Kind::Labrador: return &typeid(Labrador);
case Kind::Chihuahua: return &typeid(Chihuahua);
case Kind::LastDog: break;
case Kind::Cat: break;
case Kind::Panther: return &typeid(Panther);
case Kind::LastCat: break;
}
if (kind >= Kind::Dog && kind <= Kind::LastDog) return &typeid(Dog);
if (kind >= Kind::Cat && kind <= Kind::LastCat) return &typeid(Cat);
return nullptr;
}
std::string Animal::name_of_kind(Kind kind)
{
std::string raw_name = type_of_kind(kind)->name();
py::detail::clean_type_id(raw_name);
return raw_name;
}
namespace pybind11 {
template <typename itype>
struct polymorphic_type_hook<itype, detail::enable_if_t<std::is_base_of<Animal, itype>::value>>
{
static const void *get(const itype *src, const std::type_info*& type)
{ type = src ? Animal::type_of_kind(src->kind) : nullptr; return src; }
};
}
TEST_SUBMODULE(tagbased_polymorphic, m) {
py::class_<Animal>(m, "Animal")
.def_readonly("name", &Animal::name);
py::class_<Dog, Animal>(m, "Dog")
.def(py::init<std::string>())
.def_readwrite("sound", &Dog::sound)
.def("bark", &Dog::bark);
py::class_<Labrador, Dog>(m, "Labrador")
.def(py::init<std::string, int>(), "name"_a, "excitement"_a = 9001)
.def_readwrite("excitement", &Labrador::excitement);
py::class_<Chihuahua, Dog>(m, "Chihuahua")
.def(py::init<std::string>())
.def("bark", &Chihuahua::bark);
py::class_<Cat, Animal>(m, "Cat")
.def(py::init<std::string>())
.def("purr", &Cat::purr);
py::class_<Panther, Cat>(m, "Panther")
.def(py::init<std::string>())
.def("purr", &Panther::purr);
m.def("create_zoo", &create_zoo);
};
|