| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | #include "SharedObject.hpp" | ||
| 3 | #include "compat/gsl14.hpp" | ||
| 4 | |||
| 5 | // [The ‘clonable’ pattern](https://herbsutter.com/2019/10/03/gotw-ish-solution-the-clonable-pattern/) | ||
| 6 | // [Polymorphic clones in modern C++](https://www.fluentcpp.com/2017/09/08/make-polymorphic-copy-modern-cpp/) | ||
| 7 | // [How to Return a Smart Pointer AND Use Covariance](https://www.fluentcpp.com/2017/09/12/how-to-return-a-smart-pointer-and-use-covariance/) | ||
| 8 | |||
| 9 | template <typename Derived, typename Base = SharedObject> | ||
| 10 | class SharedCloneable : public Base { | ||
| 11 | public: | ||
| 12 | std::shared_ptr<Derived> clone() const; | ||
| 13 | 12 | ~SharedCloneable() noexcept override = default; | |
| 14 | |||
| 15 | protected: | ||
| 16 | using Base::Base; // Inherit all constructors from Base. | ||
| 17 | 6 | SharedCloneable() noexcept = default; | |
| 18 | 6 | SharedCloneable(const SharedCloneable&) = default; | |
| 19 | SharedCloneable(SharedCloneable&&) noexcept = delete; | ||
| 20 | SharedCloneable& operator=(const SharedCloneable&) = delete; | ||
| 21 | SharedCloneable& operator=(SharedCloneable&&) noexcept = delete; | ||
| 22 | |||
| 23 | private: | ||
| 24 | // NOLINTNEXTLINE(*-explicit-virtual-functions, *-use-override) | ||
| 25 | [[nodiscard]] virtual std::shared_ptr<SharedObject> cloneImpl() const; | ||
| 26 | }; | ||
| 27 | |||
| 28 | template <typename Derived, typename Base> | ||
| 29 | 4 | std::shared_ptr<Derived> SharedCloneable<Derived, Base>::clone() const { | |
| 30 |
1/2✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
8 | auto result = std::static_pointer_cast<Derived>(std::move(cloneImpl())); |
| 31 | |||
| 32 | // Derived class must override cloneImpl! | ||
| 33 |
2/4✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
|
4 | Ensures(typeid(*result) == typeid(*this)); |
| 34 | static_assert( | ||
| 35 | not(std::is_copy_constructible<Derived>::value | ||
| 36 | || std::is_move_constructible<Derived>::value | ||
| 37 | || std::is_copy_assignable<Derived>::value | ||
| 38 | || std::is_move_assignable<Derived>::value), | ||
| 39 | "Derived class must not be copy/move constructible/assignable!"); | ||
| 40 | |||
| 41 | 4 | return result; | |
| 42 | ✗ | } | |
| 43 | |||
| 44 | template <typename Derived, typename Base> | ||
| 45 | 4 | std::shared_ptr<SharedObject> SharedCloneable<Derived, Base>::cloneImpl() const { | |
| 46 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
4 | return create<Derived>(static_cast<const Derived&>(*this)); |
| 47 | } | ||
| 48 |