// // opaque_typedef.hpp // opaque-type // // Inspired by https://foonathan.github.io/blog/2016/10/19/strong-typedefs.html and others // // Created by Sam Jaffe on 8/16/16. // #pragma once #include namespace types { namespace detail { template struct is_a { FromOpaque const & self() const { return *(FromOpaque const *)(void const *)(this); } }; }} namespace types { template class... Skills> class opaque_typedef : public Skills>... { public: using super = opaque_typedef; private: Base value_; public: opaque_typedef() = default; explicit opaque_typedef(Base const & value) : value_(value) {}; explicit opaque_typedef(Base && value) : value_(std::forward(value)) {}; Base const & get() const { return value_; } explicit operator Base const &() const { return value_; } }; template struct EqualityComparable { friend bool operator==(Opaque const & lhs, Opaque const & rhs) { return lhs.get() == rhs.get(); } friend bool operator!=(Opaque const & lhs, Opaque const & rhs) { return !(lhs == rhs); } }; template struct Comparable : EqualityComparable { friend bool operator<(Opaque const & lhs, Opaque const & rhs) { return lhs.get() < rhs.get(); } friend bool operator>(Opaque const & lhs, Opaque const & rhs) { return rhs.get() < lhs.get(); } friend bool operator<=(Opaque const & lhs, Opaque const & rhs) { return !(rhs.get() < lhs.get()); } friend bool operator>=(Opaque const & lhs, Opaque const & rhs) { return !(lhs.get() < rhs.get()); } }; template struct Convertable { template class type : detail::is_a { public: operator ToOpaque() const; }; }; }