Skip to content

Instantly share code, notes, and snippets.

@npetrenko
Created September 24, 2019 16:27
Show Gist options
  • Save npetrenko/8a3e2c8ae69439a2c3b2cc124ccaf8f0 to your computer and use it in GitHub Desktop.
Save npetrenko/8a3e2c8ae69439a2c3b2cc124ccaf8f0 to your computer and use it in GitHub Desktop.
#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