浏览代码

Eliminate macros and untested operations.

Sam Jaffe 5 年之前
父节点
当前提交
6a6adad6b9
共有 3 个文件被更改,包括 81 次插入189 次删除
  1. 61 173
      opaque_typedef.hpp
  2. 0 2
      opaque_typedef.xcodeproj/project.pbxproj
  3. 20 14
      opaque_typedef_test.cpp

+ 61 - 173
opaque_typedef.hpp

@@ -11,177 +11,65 @@
 
 #include <type_traits>
 
-template <typename, typename> class opaque_typedef;
-
-template <typename Tag, typename T>
-T underlying_type_impl(opaque_typedef<Tag, T>);
-
-template <typename T>
-using underlying_type = decltype(underlying_type_impl(std::declval<T>()));
-
-#define OPAQUE_TYPE_ASSIGN_OPERATOR(name, op) \
-  template <typename TDef> \
-  struct name { \
-    friend TDef & operator op##=(TDef & lhs, TDef const & rhs) { \
-      using type = underlying_type<TDef>; \
-      static_cast<type &>(lhs) op##= static_cast<type const &>(rhs); \
-      return lhs; \
-    } \
-    \
-    friend TDef operator op(TDef const & lhs, TDef const & rhs) { \
-      using type = underlying_type<TDef>; \
-      return TDef(static_cast<type const&>(lhs) op static_cast<type const&>(rhs)); \
-    } \
-  }
-
-#define OPAQUE_TYPE_BINARY_OPERATOR_T(name, op, Out) \
-  template <typename TDef> \
-  struct name { \
-    friend Out operator op(TDef const & lhs, TDef const & rhs) { \
-      using type = underlying_type<TDef>; \
-      return Out(static_cast<type const&>(lhs) op static_cast<type const&>(rhs)); \
-    } \
-  }
-
-#define OPAQUE_TYPE_BINARY_OPERATOR(name, op) \
-  OPAQUE_TYPE_BINARY_OPERATOR_T(name, op, TDef)
-
-#define OPAQUE_TYPE_MIXED_BINARY_OPERATOR(name, op) \
-  template <typename TDef, typename RDef, typename Out> \
-  struct name { \
-    friend Out operator op(TDef const & lhs, RDef const & rhs) { \
-      using type1 = underlying_type<TDef>; \
-      using type2 = underlying_type<RDef>; \
-      return Out(static_cast<type1 const&>(lhs) op static_cast<type2 const&>(rhs)); \
-    } \
-  }; \
-  \
-  template <typename TDef, typename RDef> \
-  struct name<TDef, RDef, TDef> { \
-    friend TDef operator op##=(TDef & lhs, RDef const & rhs) { \
-      using type1 = underlying_type<TDef>; \
-      using type2 = underlying_type<RDef>; \
-      static_cast<type1 &>(lhs) op##= static_cast<type2 const&>(rhs); \
-      return lhs; \
-    } \
-    \
-    friend TDef operator op(TDef const & lhs, RDef const & rhs) { \
-      using type1 = underlying_type<TDef>; \
-      using type2 = underlying_type<RDef>; \
-      return TDef(static_cast<type1 const&>(lhs) op static_cast<type2 const&>(rhs)); \
-    } \
-  }
-
-#define OPAQUE_TYPE_UNARY_OPERATOR(name, op) \
-  template <typename TDef> \
-  struct name { \
-    friend TDef operator op(TDef const & val) { \
-      using type = underlying_type<TDef>; \
-      return TDef(op static_cast<type const&>(val)); \
-    } \
-  }
-
-OPAQUE_TYPE_UNARY_OPERATOR(unary_plus, +);
-OPAQUE_TYPE_UNARY_OPERATOR(unary_minus, -);
-
-OPAQUE_TYPE_ASSIGN_OPERATOR(addition, +);
-OPAQUE_TYPE_ASSIGN_OPERATOR(subtraction, -);
-OPAQUE_TYPE_ASSIGN_OPERATOR(multiplication, *);
-OPAQUE_TYPE_ASSIGN_OPERATOR(division, /);
-OPAQUE_TYPE_ASSIGN_OPERATOR(modulo, %);
-
-OPAQUE_TYPE_BINARY_OPERATOR_T(equals, ==, bool);
-OPAQUE_TYPE_BINARY_OPERATOR_T(not_equals, !=, bool);
-OPAQUE_TYPE_BINARY_OPERATOR_T(less_than, <, bool);
-OPAQUE_TYPE_BINARY_OPERATOR_T(less_equal, <=, bool);
-OPAQUE_TYPE_BINARY_OPERATOR_T(greater_than, >, bool);
-OPAQUE_TYPE_BINARY_OPERATOR_T(greater_equal, >=, bool);
-
-OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_addition, +);
-OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_subtraction, -);
-OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_multiplication, *);
-OPAQUE_TYPE_MIXED_BINARY_OPERATOR(mixed_division, /);
-
-OPAQUE_TYPE_ASSIGN_OPERATOR(bitwise_and, &);
-OPAQUE_TYPE_ASSIGN_OPERATOR(bitwise_or, |);
-OPAQUE_TYPE_ASSIGN_OPERATOR(exclusive_or, ^);
-
-#undef OPAQUE_TYPE_BINARY_OPERATOR_T
-#undef OPAQUE_TYPE_BINARY_OPERATOR
-#undef OPAQUE_TYPE_MIXED_BINARY_OPERATOR
-#undef OPAQUE_TYPE_UNARY_OPERATOR
-#undef OPAQUE_TYPE_ASSIGN_OPERATOR
-
-template <typename TDef>
-struct arithmetic : unary_plus<TDef>, unary_minus<TDef>, addition<TDef>, subtraction<TDef> {};
-
-template <typename TDef>
-struct numeric_arithmetic : arithmetic<TDef>, multiplication<TDef>, division<TDef> {};
-
-template <typename TDef>
-struct integer_arithmetic : numeric_arithmetic<TDef>, modulo<TDef> {};
-
-template <typename TDef, typename Base = underlying_type<TDef>>
-struct untyped_multiplication : mixed_multiplication<TDef, Base, TDef>
-, mixed_multiplication<Base, TDef, TDef> {};
-
-template <typename TDef, typename Base = underlying_type<TDef>>
-struct untyped_division : mixed_division<TDef, Base, TDef> {};
-
-template <typename TDef>
-struct equality_comparible : equals<TDef>, not_equals<TDef> {};
-
-template <typename TDef>
-struct orderable : equality_comparible<TDef>, less_than<TDef>, less_equal<TDef>, greater_than<TDef>, greater_equal<TDef> {};
-
-template <typename Self, typename T>
-class opaque_typedef {
-public:
-  opaque_typedef() : _value() {}
-  explicit opaque_typedef(T const & val) : _value(val) {}
-  explicit opaque_typedef(T && val) noexcept(std::is_nothrow_move_constructible<T>::value) : _value(std::move(val)) {}
-  explicit operator T &() noexcept { return _value; }
-  explicit operator T const&() const noexcept { return _value; }
+namespace types { namespace detail {
+  template <typename FromOpaque>
+  struct is_a {
+    FromOpaque const & self() const {
+      return *(FromOpaque const *)(void const *)(this);
+    }
+  };
+}}
+
+namespace types {
+  template <typename Base, typename Tag, template <typename> class... Skills>
+  class opaque_typedef : public Skills<opaque_typedef<Base, Tag, 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<Base>(value)) {};
+    
+    Base const & get() const { return value_; }
+    explicit operator Base const &() const { return value_; }
+  };
   
-  friend void swap(opaque_typedef & lhs, opaque_typedef & rhs) {
-    using std::swap;
-    swap(lhs._value, rhs._value);
-  }
-protected:
-  T const & self() const { return _value; }
-private:
-  T _value;
-};
-
-#include <boost/preprocessor/variadic/to_seq.hpp>
-#include <boost/preprocessor/tuple/to_seq.hpp>
-#include <boost/preprocessor/seq/for_each.hpp>
-
-#define OPAQUE_TYPEDEF_CONVERT(r, x, type) operator type() const;
-#define OPAQUE_TYPEDEF_CONVERSIONS(...) \
-    BOOST_PP_SEQ_FOR_EACH(OPAQUE_TYPEDEF_CONVERT, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
-  }
-
-#define CREATE_CONVERTABLE_OPAQUE_TYPEDEF(name, basetype, ...) \
-  struct name##_base : opaque_typedef<name, basetype> \
-  { \
-    using opaque_typedef::opaque_typedef; \
-  }; \
-  struct name : name##_base \
-  BOOST_PP_SEQ_FOR_EACH(OPAQUE_TYPEDEF_PARENT, name##_base, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
-  { \
-    using name##_base::name##_base; \
-    OPAQUE_TYPEDEF_CONVERSIONS
-
-
-#define OPAQUE_TYPEDEF_PARENT(r, name, parent) , parent < name >
-#define CREATE_OPAQUE_TYPEDEF(name, basetype, ...) \
-  struct name##_base : opaque_typedef<name, basetype> \
-  { \
-    using opaque_typedef::opaque_typedef; \
-  }; \
-  struct name : name##_base \
-  BOOST_PP_SEQ_FOR_EACH(OPAQUE_TYPEDEF_PARENT, name##_base, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
-  { \
-    using name##_base::name##_base; \
-  }
+  template <typename Opaque>
+  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 <typename Opaque>
+  struct Comparable : EqualityComparable<Opaque> {
+    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 <typename ToOpaque>
+  struct Convertable {
+    template <typename FromOpaque>
+    class type : detail::is_a<FromOpaque> {
+    public:
+      operator ToOpaque() const;
+    };
+  };
+}

+ 0 - 2
opaque_typedef.xcodeproj/project.pbxproj

@@ -8,7 +8,6 @@
 
 /* Begin PBXBuildFile section */
 		CD70490220C48B68007C944C /* opaque_typedef.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CD3C80761D63EE7800ACC795 /* opaque_typedef.hpp */; };
-		CD70490C20C48B75007C944C /* libopaque_typedef.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CD3C80681D63EE0000ACC795 /* libopaque_typedef.dylib */; };
 		CD70491220C48B7C007C944C /* opaque_typedef_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD7048F020C48AE4007C944C /* opaque_typedef_test.cpp */; };
 		CD70491520C48B8C007C944C /* GoogleMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD7048FB20C48B30007C944C /* GoogleMock.framework */; };
 /* End PBXBuildFile section */
@@ -80,7 +79,6 @@
 			buildActionMask = 2147483647;
 			files = (
 				CD70491520C48B8C007C944C /* GoogleMock.framework in Frameworks */,
-				CD70490C20C48B75007C944C /* libopaque_typedef.dylib in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 20 - 14
opaque_typedef_test.cpp

@@ -13,15 +13,21 @@
 struct degree;
 struct radian;
 
-CREATE_CONVERTABLE_OPAQUE_TYPEDEF(degree, double, orderable)(radian);
-CREATE_CONVERTABLE_OPAQUE_TYPEDEF(radian, double, orderable)(degree);
+struct degree : types::opaque_typedef<double, struct degree_tag, types::Comparable, types::Convertable<radian>::type> {
+  using super::super;
+};
+struct radian : types::opaque_typedef<double, struct radian_tag, types::Comparable, types::Convertable<degree>::type> {
+  using super::super;
+};
 
-radian::operator degree() const {
-  return degree{ self() * 90.0 / M_PI_2 };
+template<> template <>
+types::Convertable<degree>::type<radian::super>::operator degree() const {
+  return degree{ self().get() * 90.0 / M_PI_2 };
 }
 
-degree::operator radian() const {
-  return radian{ self() * M_PI_2 / 90.0 };
+template <> template <>
+types::Convertable<radian>::type<degree::super>::operator radian() const {
+  return radian{ self().get() * M_PI_2 / 90.0 };
 }
 
 void PrintTo(radian const & ot, std::ostream * os) {
@@ -42,17 +48,17 @@ TEST(OpaqueTypedefTest, Conversion) {
   EXPECT_THAT(degree(double(rad)), ::testing::Not(deg));
 }
 
-struct meters;
-struct seconds;
-struct meter_per_second;
-CREATE_OPAQUE_TYPEDEF(seconds, double, orderable);
-CREATE_OPAQUE_TYPEDEF(meter_per_second, double, orderable);
-template <typename T> using mps = mixed_division<T, seconds, meter_per_second>;
-CREATE_OPAQUE_TYPEDEF(meters, double, orderable, mps);
+using meters = types::opaque_typedef<double, struct meters_tag, types::Comparable>;
+using seconds = types::opaque_typedef<double, struct seconds_tag, types::Comparable>;
+using meter_per_second = types::opaque_typedef<double, struct mps_tag, types::Comparable>;
+
+meter_per_second operator/(meters m, seconds s) {
+  return meter_per_second{m.get() / s.get()};
+}
 
 TEST(OpaqueTypedefTest, MixedFunctions) {
   meters m{10.0};
   seconds s{0.5};
-  
+
   EXPECT_THAT(m/s, meter_per_second{20.0});
 }