Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
Go
Haskell
HLSL
Hook
Hylo
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Nim
Objective-C
Objective-C++
OCaml
OpenCL C
Pascal
Pony
Python
Racket
Ruby
Rust
Snowball
Scala
Solidity
Spice
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
Zig
Javascript
GIMPLE
cppx source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
CppCon 2017
CppCon 2018
p1240r1
p1240r2 trunk
p2320 trunk
Options
Source code
#include <memory> #include <cassert> #include <typeinfo> // An exception is thrown in case we don't override Clone(), but still call it class CloneException : public std::exception { inline const char* what() const noexcept override { return "Clone implementation has not been overriden"; } }; // Interfase class class ICloneable { public: inline std::unique_ptr<ICloneable> IClone() const { return std::unique_ptr<ICloneable>(ICloneImpl()); } virtual ~ICloneable() = default; protected: virtual ICloneable* ICloneImpl() const = 0; }; // Basically a helper class for stong-typing arguments template <class... inherit_from> struct InheritFrom : public inherit_from... {}; template <class T> struct InheritFrom<T> : public T { using T::T; }; template <class... inherit_from> struct InheritFromVirtual : public virtual inherit_from... {}; // Helpers to assert that the inheritance is done in the right way namespace type_traits { template <class T> struct IsInheritFrom { static constexpr bool value = false; }; template <class... T> struct IsInheritFrom<InheritFrom<T...>> { static constexpr bool value = true; }; template <class T> struct IsInheritFromVirtual { static constexpr bool value = false; }; template <class... T> struct IsInheritFromVirtual<InheritFromVirtual<T...>> { static constexpr bool value = true; }; template <class T> inline constexpr bool IsInheritFrom_v = IsInheritFrom<T>::value || IsInheritFromVirtual<T>::value; template <class T> inline constexpr bool IsInheritFromVirtual_v = IsInheritFromVirtual<T>::value; } // And here comes the implementation... template <class Derived, class AnotherBase, bool derived_is_abstract, bool base_is_cloneable = std::is_base_of_v<ICloneable, AnotherBase>> class _CloneableImpl; #define __CloneImpl \ public: \ inline std::unique_ptr<Derived> Clone() const { \ auto ptr = this->ICloneImpl(); \ return std::unique_ptr<Derived>{static_cast<Derived*>(ptr)}; \ } \ \ protected: \ inline _CloneableImpl* ICloneImpl() const override { \ if (typeid(*this) != typeid(Derived)) { \ throw CloneException(); \ } \ auto ret = new Derived(static_cast<const Derived&>(*this)); \ return static_cast<std::remove_reference_t<decltype(*ret)>*>(ret); \ } \ \ private: #define __CloneImplAbstract \ public: \ inline std::unique_ptr<Derived> Clone() const { \ auto ptr = this->ICloneImpl(); \ return std::unique_ptr<Derived>{dynamic_cast<Derived*>(ptr)}; \ } \ \ private: // three identical implementations, only the inheritance is different #define Implement(IsAbstract, ImplType) \ /* "no base is defined" case*/ \ template <class Derived> \ class _CloneableImpl<Derived, void, IsAbstract, false> : public virtual ICloneable { \ ImplType \ }; \ \ /* Base is defined, and already provides ICloneable*/ \ template <class Derived, class AnotherBase> \ class _CloneableImpl<Derived, AnotherBase, IsAbstract, true> : public AnotherBase { \ static_assert(type_traits::IsInheritFrom_v<AnotherBase>, \ "Inheritance in EnableClone can only be done through InheritFrom...<...>"); \ \ public: \ using AnotherBase::AnotherBase; \ ImplType \ }; \ \ /* Base is defined, but has no ICloneable*/ \ template <class Derived, class AnotherBase> \ class _CloneableImpl<Derived, AnotherBase, IsAbstract, false> : public AnotherBase, \ public virtual ICloneable { \ static_assert(type_traits::IsInheritFrom_v<AnotherBase>, \ "Inheritance in EnableClone can only be done through InheritFrom...<...>"); \ \ public: \ using AnotherBase::AnotherBase; \ ImplType \ }; Implement(false, __CloneImpl) Implement(true, __CloneImplAbstract) #undef __CloneImpl #undef __CloneImplAbstract #undef Implement // CRTP for non-abstract base template <class Derived, class AnotherBase = void> class EnableClone : public _CloneableImpl<Derived, AnotherBase, false> { using _CloneableImpl<Derived, AnotherBase, false>::_CloneableImpl; }; // CRTP for abstract base template <class Derived, class AnotherBase = void> class EnableCloneInterface : public _CloneableImpl<Derived, AnotherBase, true> { using _CloneableImpl<Derived, AnotherBase, true>::_CloneableImpl; }; class Base : public EnableClone<Base> { public: Base() = default; virtual int GetVal() { return 0; } private: }; class Derived : public EnableClone<Derived, InheritFrom<Base>> { public: explicit Derived(int val) : val_(val) {} int GetVal() override { return val_; } private: int val_; }; class NoCloneDerived : public Base { }; int main () { // Covariant return type for unique_ptr { Derived d(10); std::unique_ptr<Derived> d_ptr = d.Clone(); assert(d_ptr->GetVal() == 10); } // Indeed does a proper clone { Derived d(10); std::unique_ptr<Base> d_ptr = static_cast<Base&>(d).Clone(); assert(d_ptr->GetVal() == 10); } // Throws an exception if the method has not been overriden { NoCloneDerived d; try { auto not_gonna_get_it = d.Clone(); // this assert never fires assert(false); } catch (CloneException&) { } } }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
About the author
Statistics
Changelog
Version tree