zeusUnnamed repository; edit this file 'description' to name the repository. |
git clone Unknown |
Log | Files | Refs |
decorator_units.cpp (3083B)
0 #include <cassert>
1 #include <iostream>
2 #include <memory>
3 #include <type_traits>
4 #include <utility>
6 template <class Callable> class DebugDecorator {
7 Callable m_callable;
8 const char *m_s;
10 public:
11 template <class F>
12 DebugDecorator(F &&f, const char *s)
13 : m_callable(std::forward<F>(f)), m_s(s) {}
15 template <class... Args> auto operator()(Args &&...args) const {
16 std::cout << "Invoking " << m_s << std::endl;
18 using res_t = std::invoke_result_t<Callable, Args...>;
19 if constexpr (!std::is_same_v<res_t, void>) {
20 auto res = m_callable(std::forward<Args>(args)...);
21 std::cout << "Result: " << res << std::endl;
22 return res;
23 } else {
24 m_callable(std::forward<Args>(args)...);
25 }
26 }
27 };
29 template <class Callable> auto decorate_debug(Callable &&c, const char *s) {
30 return DebugDecorator<Callable>(std::forward<Callable>(c), s);
31 }
33 template <class To, class From> auto move_cast(std::unique_ptr<From> &p) {
34 #ifndef NDEBUG
35 auto p1 = std::unique_ptr<To>(dynamic_cast<To *>(p.release()));
36 assert(p1);
37 return p1;
38 #else
39 return std::unique_ptr<To>(static_cast<To *>(p.release()));
40 #endif
41 }
43 class Unit {
44 protected:
45 double m_strength;
46 double m_armor;
48 public:
49 virtual ~Unit() = default;
51 Unit(double strength, double armor) : m_strength(strength), m_armor(armor) {}
53 virtual double defense() = 0;
54 virtual double attack() = 0;
56 virtual bool hit(Unit &target) { return attack() > target.defense(); }
57 };
59 class Knight : public Unit {
60 protected:
61 static constexpr double sword_bonus = 2;
62 static constexpr double plate_bonus = 3;
64 double m_charge_bonus = 0;
66 public:
67 using Unit::Unit;
69 double defense() override { return m_armor + plate_bonus; }
70 double attack() override {
71 const auto res = m_strength + sword_bonus + m_charge_bonus;
72 m_charge_bonus = 0;
73 return res;
74 }
76 void charge() { m_charge_bonus = 1; }
77 };
79 class Ogre : public Unit {
80 protected:
81 static constexpr double club_penalty = -1;
82 static constexpr double leather_penalty = -1;
84 public:
85 using Unit::Unit;
87 double defense() override { return m_armor + leather_penalty; }
88 double attack() override { return m_strength + club_penalty; }
89 };
91 template <class U> class VeteranUnit : public U {
92 double m_strength_bonus;
93 double m_armor_bonus;
95 public:
96 template <class P>
97 VeteranUnit(P &&p, double strength_bonus, double armor_bonus)
98 : U(std::move(*move_cast<U>(p))), m_strength_bonus(strength_bonus),
99 m_armor_bonus(armor_bonus) {}
101 double defense() override { return U::defense() + m_armor_bonus; }
102 double attack() override { return U::attack() + m_strength_bonus; }
103 };
105 int main() {
106 using Unit_ptr = std::unique_ptr<Unit>;
107 using Knight_ptr = std::unique_ptr<Knight>;
108 using Ogre_ptr = std::unique_ptr<Ogre>;
110 Knight_ptr k(new Knight(10, 5));
111 Unit_ptr o(new Ogre(12, 2));
113 Knight_ptr vk(new VeteranUnit<Knight>(k, 7, 2));
114 Unit_ptr vo(new VeteranUnit<Ogre>(o, 1, 9));
115 Unit_ptr vvo(new VeteranUnit<VeteranUnit<Ogre>>(vo, 1, 9));
117 vk->hit(*vvo);
118 vk->charge();
119 vk->hit(*vvo);
121 return 0;
122 }