opaque_typedef.hpp 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. //
  2. // opaque_typedef.hpp
  3. // opaque-type
  4. //
  5. // Inspired by https://foonathan.github.io/blog/2016/10/19/strong-typedefs.html and others
  6. //
  7. // Created by Sam Jaffe on 8/16/16.
  8. //
  9. #pragma once
  10. #include <type_traits>
  11. namespace types { namespace detail {
  12. template <typename FromOpaque>
  13. struct is_a {
  14. FromOpaque const & self() const {
  15. return *(FromOpaque const *)(void const *)(this);
  16. }
  17. };
  18. }}
  19. namespace types {
  20. template <typename Base, typename Tag, template <typename> class... Skills>
  21. class opaque_typedef : public Skills<opaque_typedef<Base, Tag, Skills...>>... {
  22. public:
  23. using super = opaque_typedef;
  24. private:
  25. Base value_;
  26. public:
  27. opaque_typedef() = default;
  28. explicit opaque_typedef(Base const & value) : value_(value) {};
  29. explicit opaque_typedef(Base && value) : value_(std::forward<Base>(value)) {};
  30. Base const & get() const { return value_; }
  31. explicit operator Base const &() const { return value_; }
  32. };
  33. template <typename Opaque>
  34. struct EqualityComparable {
  35. friend bool operator==(Opaque const & lhs, Opaque const & rhs) {
  36. return lhs.get() == rhs.get();
  37. }
  38. friend bool operator!=(Opaque const & lhs, Opaque const & rhs) {
  39. return !(lhs == rhs);
  40. }
  41. };
  42. template <typename Opaque>
  43. struct Comparable : EqualityComparable<Opaque> {
  44. friend bool operator<(Opaque const & lhs, Opaque const & rhs) {
  45. return lhs.get() < rhs.get();
  46. }
  47. friend bool operator>(Opaque const & lhs, Opaque const & rhs) {
  48. return rhs.get() < lhs.get();
  49. }
  50. friend bool operator<=(Opaque const & lhs, Opaque const & rhs) {
  51. return !(rhs.get() < lhs.get());
  52. }
  53. friend bool operator>=(Opaque const & lhs, Opaque const & rhs) {
  54. return !(lhs.get() < rhs.get());
  55. }
  56. };
  57. template <typename ToOpaque>
  58. struct Convertable {
  59. template <typename FromOpaque>
  60. class type : detail::is_a<FromOpaque> {
  61. public:
  62. operator ToOpaque() const;
  63. };
  64. };
  65. }