Created
September 24, 2019 16:27
-
-
Save npetrenko/8a3e2c8ae69439a2c3b2cc124ccaf8f0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <cassert> | |
template <class T> | |
struct Clone { | |
template <class Dummy = void> | |
auto operator()(const T& val) const { | |
static_assert(!std::is_same_v<Dummy, void>, "Clone trait not implemented"); | |
} | |
}; | |
template <class T> | |
using CloneType = decltype(Clone<T>()(std::declval<const T&>())); | |
template <class Derived> | |
class Base { | |
public: | |
int Create() const { | |
return static_cast<const Derived&>(*this).CreateImpl(); | |
} | |
}; | |
template <class Derived> | |
struct Clone<Base<Derived>> { | |
auto operator()(const Base<Derived>& base) const { | |
return Clone<Derived>()(static_cast<const Derived&>(base)); | |
} | |
}; | |
template <class T> | |
CloneType<T> DoClone(const T& val) { | |
return Clone<T>()(val); | |
} | |
class Derived : public Base<Derived> { | |
public: | |
explicit Derived(int val) : val_(val) { | |
} | |
private: | |
friend Base<Derived>; | |
int CreateImpl () const { | |
return val_; | |
} | |
int val_; | |
}; | |
class BadDerive : public Base<BadDerive> { | |
friend class Base<BadDerive>; | |
int CreateImpl() const { | |
return 0; | |
} | |
}; | |
template<> | |
struct Clone<Derived> { | |
Derived operator()(const Derived& val) const { | |
return val; | |
} | |
}; | |
template <class T> | |
CloneType<T> CloneTest(const Base<T>& obj) { | |
return DoClone(obj); | |
} | |
int main() { | |
{ | |
Derived d{10}; | |
auto cloned = CloneTest(d); | |
static_assert(std::is_same_v<decltype(cloned), Derived>); | |
static_assert(std::is_same_v<decltype(cloned), CloneType<Derived>>); | |
assert(cloned.Create() == d.Create()); | |
} | |
// Does not compile (as intended), with a readable error: | |
/* | |
{ | |
BadDerive bad; | |
auto cloned = CloneTest(bad); | |
} | |
*/ | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment