test_tagbased_polymorphic.cpp
Go to the documentation of this file.
1 /*
2  tests/test_tagbased_polymorphic.cpp -- test of polymorphic_type_hook
3 
4  Copyright (c) 2018 Hudson River Trading LLC <opensource@hudson-trading.com>
5 
6  All rights reserved. Use of this source code is governed by a
7  BSD-style license that can be found in the LICENSE file.
8 */
9 
10 #include "pybind11_tests.h"
11 #include <pybind11/stl.h>
12 
13 struct Animal
14 {
15  // Make this type also a "standard" polymorphic type, to confirm that
16  // specializing polymorphic_type_hook using enable_if_t still works
17  // (https://github.com/pybind/pybind11/pull/2016/).
18  virtual ~Animal() = default;
19 
20  // Enum for tag-based polymorphism.
21  enum class Kind {
22  Unknown = 0,
23  Dog = 100, Labrador, Chihuahua, LastDog = 199,
24  Cat = 200, Panther, LastCat = 299
25  };
26  static const std::type_info* type_of_kind(Kind kind);
27  static std::string name_of_kind(Kind kind);
28 
29  const Kind kind;
30  const std::string name;
31 
32  protected:
33  Animal(const std::string& _name, Kind _kind)
34  : kind(_kind), name(_name)
35  {}
36 };
37 
38 struct Dog : Animal
39 {
40  Dog(const std::string& _name, Kind _kind = Kind::Dog) : Animal(_name, _kind) {}
41  std::string bark() const { return name_of_kind(kind) + " " + name + " goes " + sound; }
42  std::string sound = "WOOF!";
43 };
44 
45 struct Labrador : Dog
46 {
47  Labrador(const std::string& _name, int _excitement = 9001)
48  : Dog(_name, Kind::Labrador), excitement(_excitement) {}
50 };
51 
52 struct Chihuahua : Dog
53 {
54  Chihuahua(const std::string& _name) : Dog(_name, Kind::Chihuahua) { sound = "iyiyiyiyiyi"; }
55  std::string bark() const { return Dog::bark() + " and runs in circles"; }
56 };
57 
58 struct Cat : Animal
59 {
60  Cat(const std::string& _name, Kind _kind = Kind::Cat) : Animal(_name, _kind) {}
61  std::string purr() const { return "mrowr"; }
62 };
63 
64 struct Panther : Cat
65 {
66  Panther(const std::string& _name) : Cat(_name, Kind::Panther) {}
67  std::string purr() const { return "mrrrRRRRRR"; }
68 };
69 
70 std::vector<std::unique_ptr<Animal>> create_zoo()
71 {
72  std::vector<std::unique_ptr<Animal>> ret;
73  ret.emplace_back(new Labrador("Fido", 15000));
74 
75  // simulate some new type of Dog that the Python bindings
76  // haven't been updated for; it should still be considered
77  // a Dog, not just an Animal.
78  ret.emplace_back(new Dog("Ginger", Dog::Kind(150)));
79 
80  ret.emplace_back(new Chihuahua("Hertzl"));
81  ret.emplace_back(new Cat("Tiger", Cat::Kind::Cat));
82  ret.emplace_back(new Panther("Leo"));
83  return ret;
84 }
85 
86 const std::type_info* Animal::type_of_kind(Kind kind)
87 {
88  switch (kind) {
89  case Kind::Unknown: break;
90 
91  case Kind::Dog: break;
92  case Kind::Labrador: return &typeid(Labrador);
93  case Kind::Chihuahua: return &typeid(Chihuahua);
94  case Kind::LastDog: break;
95 
96  case Kind::Cat: break;
97  case Kind::Panther: return &typeid(Panther);
98  case Kind::LastCat: break;
99  }
100 
101  if (kind >= Kind::Dog && kind <= Kind::LastDog) return &typeid(Dog);
102  if (kind >= Kind::Cat && kind <= Kind::LastCat) return &typeid(Cat);
103  return nullptr;
104 }
105 
107 {
108  std::string raw_name = type_of_kind(kind)->name();
109  py::detail::clean_type_id(raw_name);
110  return raw_name;
111 }
112 
113 namespace pybind11 {
114  template <typename itype>
115  struct polymorphic_type_hook<itype, detail::enable_if_t<std::is_base_of<Animal, itype>::value>>
116  {
117  static const void *get(const itype *src, const std::type_info*& type)
118  { type = src ? Animal::type_of_kind(src->kind) : nullptr; return src; }
119  };
120 } // namespace pybind11
121 
122 TEST_SUBMODULE(tagbased_polymorphic, m) {
123  py::class_<Animal>(m, "Animal")
124  .def_readonly("name", &Animal::name);
125  py::class_<Dog, Animal>(m, "Dog")
126  .def(py::init<std::string>())
127  .def_readwrite("sound", &Dog::sound)
128  .def("bark", &Dog::bark);
129  py::class_<Labrador, Dog>(m, "Labrador")
130  .def(py::init<std::string, int>(), "name"_a, "excitement"_a = 9001)
131  .def_readwrite("excitement", &Labrador::excitement);
132  py::class_<Chihuahua, Dog>(m, "Chihuahua")
133  .def(py::init<std::string>())
134  .def("bark", &Chihuahua::bark);
135  py::class_<Cat, Animal>(m, "Cat")
136  .def(py::init<std::string>())
137  .def("purr", &Cat::purr);
138  py::class_<Panther, Cat>(m, "Panther")
139  .def(py::init<std::string>())
140  .def("purr", &Panther::purr);
141  m.def("create_zoo", &create_zoo);
142 };
Matrix3f m
std::vector< std::unique_ptr< Animal > > create_zoo()
Panther(const std::string &_name)
Animal(const std::string &_name, Kind _kind)
std::string bark() const
TEST_SUBMODULE(tagbased_polymorphic, m)
PYBIND11_NOINLINE void clean_type_id(std::string &name)
Definition: typeid.h:32
static const std::type_info * type_of_kind(Kind kind)
std::string purr() const
std::string bark() const
Dog(const std::string &_name, Kind _kind=Kind::Dog)
static std::string name_of_kind(Kind kind)
Chihuahua(const std::string &_name)
const std::string name
DenseIndex ret
Definition: level1_impl.h:59
typename std::enable_if< B, T >::type enable_if_t
from cpp_future import (convenient aliases from C++14/17)
Annotation for function names.
Definition: attr.h:36
virtual ~Animal()=default
Cat(const std::string &_name, Kind _kind=Kind::Cat)
std::string sound
std::string purr() const
Labrador(const std::string &_name, int _excitement=9001)


gtsam
Author(s):
autogenerated on Sat May 8 2021 02:46:04