Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C with Coccinelle
C++ with Coccinelle
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#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Mojo
Nim
Numba
Nix
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
PTX
Python
Racket
Raku
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Zig
Javascript
GIMPLE
Ygen
sway
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
CE on Bluesky
About the author
Statistics
Changelog
Version tree