Prechádzať zdrojové kódy

Fixing SFINAE resolution

Samuel Jaffe 9 rokov pred
rodič
commit
2d5980e8d1
3 zmenil súbory, kde vykonal 142 pridanie a 117 odobranie
  1. 107 95
      vector.hpp
  2. 33 22
      vector.t.h
  3. 2 0
      vector.xcodeproj/project.pbxproj

+ 107 - 95
vector.hpp

@@ -16,6 +16,8 @@
 #include <stdexcept>
 #include <type_traits>
 
+#include "expect/expect.hpp"
+
 namespace math { namespace vector {
 #define VECTOR_ENABLE_IF_LT_N(index, expr) \
 template <bool _ = true> \
@@ -24,21 +26,33 @@ typename std::enable_if<std::size_t(index) < N && _, expr>::type
 #define VECTOR_ENABLE_IF_EQ_N(index, t, n) \
 template <bool _ = true> \
 typename std::enable_if<std::size_t(index) == N && _, vector<t, n> >::type
-
+  
 #define VECTOR_ENABLE_IF_EQ_T(_type, t, n) \
-vector<typename std::enable_if<std::is_same<_type, T>::value,T>::type, N>
+typename std::enable_if<std::is_same<_type, t>::value, vector<t, n> >::type
+  
+#define VECTOR_DISABLE_IF_VECTOR(_type, t, n) \
+typename std::enable_if<!is_vector<_type>::value, vector<t, n> >::type
   
 #define VECTOR_ACCESS_FN(name, i) \
 VECTOR_ENABLE_IF_LT_N(i, value_type const &) name() const { return _data[i]; } \
 VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
   
-#define VECTOR_FOR_EACH(var) for (std::size_t var = 0; var < N; ++var)
+#define VECTOR_FOR_EACH_RANGE(var, end) for (std::size_t var = 0; var < end; ++var)
+#define VECTOR_FOR_EACH(var) VECTOR_FOR_EACH_RANGE(var, N)
   
   struct {} fill;
   using fill_t = decltype(fill);
   
+  template <typename T>
+  struct is_vector { static const constexpr bool value = false; };
+  
+  template <typename T, std::size_t N>
+  class vector;
+  template <typename T, std::size_t N>
+  struct is_vector<vector<T, N>> { static const constexpr bool value = true; };
+  
   template <typename T, std::size_t N>
-  struct vector {
+  class vector {
   public:
     using value_type = T;
   private:
@@ -51,20 +65,23 @@ VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
     
     // Constructors
     vector() = default;
+    
     vector(std::initializer_list<T> && init) {
+      expects(init.size() == N, "initializer size mismatch");
       std::size_t idx = 0;
       for ( auto it = init.begin(), end = init.end(); it != end && idx < N; ++it, ++idx ) {
         _data[idx] = *it;
       }
     }
+    
     vector(std::array<T, N> const & init) {
-      for (std::size_t i = 0; i < N && i < init.size(); ++i) {
-        _data[i] = init[i];
-      }
+      VECTOR_FOR_EACH(i) { _data[i] = init[i]; }
     }
+    
     vector(vector const & other) {
       *this = other;
     }
+    
     vector(vector && other) {
       *this = std::move(other);
     }
@@ -72,10 +89,11 @@ VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
     // Conversion
     template <typename T2, std::size_t N2>
     explicit vector(vector<T2, N2> const & other) {
-      for (std::size_t i = 0; i < N && i < N2; ++i) {
+      VECTOR_FOR_EACH_RANGE(i, std::min(N, N2)) {
         _data[i] = static_cast<T>(other[i]);
       }
     }
+    
     vector(T const & v, fill_t) {
       VECTOR_FOR_EACH(i) { _data[i] = v; }
     }
@@ -85,6 +103,7 @@ VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
       VECTOR_FOR_EACH(i) { _data[i] = other[i]; }
       return *this;
     }
+    
     vector& operator=(vector && other) {
       VECTOR_FOR_EACH(i) { _data[i] = std::move(other._data[i]); }
       return *this;
@@ -104,110 +123,101 @@ VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
     VECTOR_ACCESS_FN(a, 3)
     
     // Unnamed Accessors
-    value_type const & operator[](std::size_t idx) const { return _data[idx]; }
-    value_type & operator[](std::size_t idx) { return _data[idx]; }
+    value_type const & operator[](std::size_t idx) const {
+      return _data[idx];
+    }
+    
+    value_type & operator[](std::size_t idx) {
+      return _data[idx];
+    }
     
     value_type const & at(std::size_t idx) const {
-      if (idx >= N) throw std::out_of_range{"index out of range"};
-      assert(idx < N);
-      return operator[](idx);
+      expects(idx < N, std::out_of_range, "index out of range");
+      return _data[idx];
     }
+    
     value_type & at(std::size_t idx) {
-      if (idx >= N) throw std::out_of_range{"index out of range"};
-      assert(idx < N);
-      return operator[](idx);
+      expects(idx < N, std::out_of_range, "index out of range");
+      return _data[idx];
     }
     
     // Mathematical Operations
     vector& operator+=(vector const & other) {
-      VECTOR_FOR_EACH(i) {
-        _data[i] += other[i];
-      }
+      VECTOR_FOR_EACH(i) { _data[i] += other[i]; }
       return *this;
     }
     
-    vector& operator-=(vector const & other) {
-      VECTOR_FOR_EACH(i) {
-        _data[i] -= other[i];
-      }
-      return *this;
+    vector operator+(vector const & other) const {
+      return vector{*this} += other;
     }
     
-    template <typename M>
-    VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N)& operator*=(M c) {
-      VECTOR_FOR_EACH(i) {
-        _data[i] *= c;
-      }
+    vector& operator-=(vector const & other) {
+      VECTOR_FOR_EACH(i) { _data[i] -= other[i]; }
       return *this;
     }
     
-    template <typename M>
-    VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N)& operator/=(M c) {
-      VECTOR_FOR_EACH(i) {
-        _data[i] /= c;
-      }
-      return *this;
+    vector operator-(vector const & other) const {
+      return vector{*this} -= other;
     }
     
-    template <typename M>
-    VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N)& operator*=(vector<M, N> c) {
-      VECTOR_FOR_EACH(i) {
-        _data[i] *= c[i];
-      }
-      return *this;
+    vector operator-() const {
+      return vector{} -= *this;
     }
     
     template <typename M>
-    VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N)& operator/=(vector<M, N> c) {
-      VECTOR_FOR_EACH(i) {
-        _data[i] /= c[i];
-      }
+    VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N)& operator*=(M c) {
+      VECTOR_FOR_EACH(i) { _data[i] *= c; }
       return *this;
     }
-      
-    vector operator+(vector const & other) const {
-      return vector{*this} += other;
-    }
     
-    vector operator-(vector const & other) const {
-      return vector{*this} -= other;
+    template <typename M>
+    VECTOR_DISABLE_IF_VECTOR(M, mul_t<M>, N) operator*(M c) const {
+      return vector<mul_t<M>, N>{*this} *= c;
     }
     
     template <typename M>
-    vector<mul_t<M>, N> scaled(vector<M, N> const & other) const {
-      return vector<mul_t<M>, N>{*this} *= other;
+    friend VECTOR_DISABLE_IF_VECTOR(M, mul_t<M>, N) operator*(M c, vector<T, N> const & v) {
+      return v * c;
     }
     
     template <typename M>
-    vector<mul_t<M>, N> operator*(M c) const {
+    VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N)& operator*=(vector<M, N> c) {
       return vector<mul_t<M>, N>{*this} *= c;
     }
     
     template <typename M>
-    friend vector<mul_t<M>, N> operator*(M c, vector<T, N> const & v) {
-      return v * c;
+    vector<mul_t<M>, N> operator*(vector<M, N> const & other) const {
+      return vector<mul_t<M>, N>{*this} *= other;
     }
     
     template <typename M>
-    vector<div_t<M>, N> invscaled(vector<M, N> const & other) const {
-      return vector<div_t<M>, N>{*this} /= other;
+    VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N)& operator/=(M c) {
+      expects(c != 0, std::domain_error, "divide by zero");
+      VECTOR_FOR_EACH(i) { _data[i] /= c; }
+      return *this;
     }
     
     template <typename M>
-    vector<div_t<M>, N> operator/(M c) const {
+    VECTOR_DISABLE_IF_VECTOR(M, div_t<M>, N) operator/(M c) const {
       return vector<div_t<M>, N>{*this} /= c;
     }
     
-    vector operator-() const {
-      return vector{} -= *this;
+    template <typename M>
+    VECTOR_ENABLE_IF_EQ_T(div_t<M>, T, N)& operator/=(vector<M, N> c) {
+      VECTOR_FOR_EACH(i) { expects(c[i] != 0, std::domain_error, "divide by zero"); }
+      VECTOR_FOR_EACH(i) { _data[i] /= c[i]; }
+      return *this;
+    }
+    
+    template <typename M>
+    vector<div_t<M>, N> operator/(vector<M, N> const & other) const {
+      return vector<div_t<M>, N>{*this} /= other;
     }
     
     // Vector Operations
     value_type dot(vector const & other) const {
       value_type accum{};
-      VECTOR_FOR_EACH(i) {
-        accum += at(i) * other.at(i);
-      }
+      VECTOR_FOR_EACH(i) { accum += at(i) * other.at(i); }
       return accum;
     }
     
@@ -219,21 +229,6 @@ VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
       return *this / magnitude();
     }
     
-    friend vector abs(vector const & self) {
-      vector tmp(self);
-      using std::abs;
-      for (std::size_t i = 0; i < N; ++i) {
-        tmp._data[i] = abs(tmp._data[i]);
-      }
-      return tmp;
-    }
-    
-    friend void swap(vector & lhs, vector & rhs) {
-      vector tmp(lhs);
-      lhs = rhs;
-      rhs = tmp;
-    }
-    
     VECTOR_ENABLE_IF_EQ_N(3, T, N) cross(vector const & other) const {
       return {
         y()*other.z() - z()*other.y(),
@@ -241,6 +236,7 @@ VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
         x()*other.y() - y()*other.x()
       };
     }
+    
     VECTOR_ENABLE_IF_EQ_N(2, T, 3) cross(vector const & other) const {
       return { 0, 0, x()*other.y() - y()*other.x() };
     }
@@ -250,23 +246,39 @@ VECTOR_ENABLE_IF_LT_N(i, value_type &) name() { return _data[i]; }
       return b_p * vector<mag_t, N>{*this}.dot(b_p);
     }
     
-    friend bool operator==(vector const & lhs, vector const & rhs) { return lhs.compare(rhs) == 0; }
-    friend bool operator!=(vector const & lhs, vector const & rhs) { return lhs.compare(rhs) != 0; }
-    friend bool operator< (vector const & lhs, vector const & rhs) { return lhs.compare(rhs) <  0; }
-    friend bool operator<=(vector const & lhs, vector const & rhs) { return lhs.compare(rhs) <= 0; }
-    friend bool operator> (vector const & lhs, vector const & rhs) { return lhs.compare(rhs) >  0; }
-    friend bool operator>=(vector const & lhs, vector const & rhs) { return lhs.compare(rhs) >= 0; }
-    
   private:
-    int compare(vector const & other) const {
-      int rv = 0;
-      for (std::size_t i = 0; i < N && rv == 0; ++i) {
-        if (_data[i] < other[i]) rv = -1;
-        else if (_data[i] > other[i]) rv = 1;
-      }
-      return rv;
-    }
-    
     value_type _data[N] = {value_type()};
   };
+  
+  template <typename T, std::size_t N>
+  vector<T, N> abs(vector<T, N> const & self) {
+    vector<T, N> tmp(self);
+    using std::abs;
+    VECTOR_FOR_EACH(i) { tmp[i] = abs(tmp[i]); }
+    return tmp;
+  }
+  
+  template <typename T, std::size_t N>
+  int compare(vector<T, N> const & lhs, vector<T, N> const & rhs) {
+    VECTOR_FOR_EACH(i) {
+      if (lhs[i] < rhs[i]) return -1;
+      else if (lhs[i] > rhs[i]) return 1;
+    }
+    return 0;
+  }
+  
+  template <typename T, std::size_t N>
+  bool operator==(vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) == 0; }
+  template <typename T, std::size_t N>
+  bool operator!=(vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) != 0; }
+  template <typename T, std::size_t N>
+  bool operator< (vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) <  0; }
+  template <typename T, std::size_t N>
+  bool operator<=(vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) <= 0; }
+  template <typename T, std::size_t N>
+  bool operator> (vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) >  0; }
+  template <typename T, std::size_t N>
+  bool operator>=(vector<T, N> const & lhs, vector<T, N> const & rhs) { return compare(lhs, rhs) >= 0; }
 } }
+
+using math::vector::abs;

+ 33 - 22
vector.t.h

@@ -8,7 +8,12 @@ public:
   using vec3  = math::vector::vector<double, 3>;
   using vec3i = math::vector::vector<int, 3>;
   using vec4i = math::vector::vector<int, 4>;
-
+  
+  void test_vector_badsize_throws() const {
+    TS_ASSERT_THROWS((vec2i{1}), std::logic_error);
+    TS_ASSERT_THROWS((vec2i{1,1,1}), std::logic_error);
+  }
+  
   void test_vector_equals() const {
     TS_ASSERT_EQUALS(iota3i(), (vec3i{1, 2, 3}));
   }
@@ -53,20 +58,25 @@ public:
   }
   
   void test_vector_multiplication_vector() const {
-    TS_ASSERT_EQUALS((vec2i{1,0}.scaled(vec2i{2,1})), (vec2i{2,0}))
+    TS_ASSERT_EQUALS((vec2i{1,0}*(vec2i{2,1})), (vec2i{2,0}))
   }
   
   void test_vector_divides_vector() const {
-    TS_ASSERT_EQUALS((vec2i{6,4}.invscaled(vec2i{2,1})), (vec2i{3,4}))
+    TS_ASSERT_EQUALS((vec2i{6,4}/(vec2i{2,1})), (vec2i{3,4}))
+  }
+  
+  void test_divide_by_zero_fails() const {
+    TS_ASSERT_THROWS(vec3{} / 0, std::domain_error);
+    TS_ASSERT_THROWS((vec3{1.0, 1.0, 1.0}/(vec3{1.0, 0.5, 0.0})), std::domain_error);
   }
   
-//  void test_vector_addition_value() const {
-//    TS_ASSERT_EQUALS((vec2i{1,0} + 1), (vec2i{2,1}))
-//  }
-//  
-//  void test_vector_subtraction_value() const {
-//    TS_ASSERT_EQUALS((vec2i{1,0} - 1), (vec2i{0,-1}))
-//  }
+  //  void test_vector_addition_value() const {
+  //    TS_ASSERT_EQUALS((vec2i{1,0} + 1), (vec2i{2,1}))
+  //  }
+  //
+  //  void test_vector_subtraction_value() const {
+  //    TS_ASSERT_EQUALS((vec2i{1,0} - 1), (vec2i{0,-1}))
+  //  }
   
   void test_vector_multiplication_value() const {
     TS_ASSERT_EQUALS((vec2i{1,0} * 3), (vec2i{3,0}))
@@ -76,29 +86,29 @@ public:
     TS_ASSERT_EQUALS((vec2i{6,4} / 2), (vec2i{3,2}))
   }
   
-//  void test_value_addition_vector() const {
-//    TS_ASSERT_EQUALS(1+iota2i(), (vec2i{2,3}));
-//  }
-//  
-//  void test_value_subtraction_vector() const {
-//    TS_ASSERT_EQUALS(4-iota2i(), (vec2i{3,2}));
-//  }
+  //  void test_value_addition_vector() const {
+  //    TS_ASSERT_EQUALS(1+iota2i(), (vec2i{2,3}));
+  //  }
+  //
+  //  void test_value_subtraction_vector() const {
+  //    TS_ASSERT_EQUALS(4-iota2i(), (vec2i{3,2}));
+  //  }
   
   void test_value_multiplication_vector() const {
     TS_ASSERT_EQUALS(2*iota2i(), (vec2i{2,4}));
   }
   
-//  void test_value_divides_vector() const {
-//    TS_ASSERT_EQUALS(4/iota2i(), (vec2i{4,2}));
-//  }
+  //  void test_value_divides_vector() const {
+  //    TS_ASSERT_EQUALS(4/iota2i(), (vec2i{4,2}));
+  //  }
   
   void test_length_of_vector() const {
-//    TS_ASSERT_EQUALS(iota3i().lengthSquared(), 14);
+    //    TS_ASSERT_EQUALS(iota3i().lengthSquared(), 14);
     TS_ASSERT_DELTA(iota3i().magnitude(), std::sqrt(14), 0.00001);
   }
   
   void test_distance_of_vector() const {
-//    TS_ASSERT_EQUALS((iota3i().distanceSquared(vec3i{3, 1, -1})), 21);
+    //    TS_ASSERT_EQUALS((iota3i().distanceSquared(vec3i{3, 1, -1})), 21);
     TS_ASSERT_DELTA((iota3i() - vec3i{3, 1, -1}).magnitude(), std::sqrt(21), 0.00001);
   }
   
@@ -121,6 +131,7 @@ public:
   }
   
   void test_swap() const {
+    using std::swap;
     vec2i a{1, 2}; const vec2i ac = a;
     vec2i b{5, 7}; const vec2i bc = b;
     swap(a, b);

+ 2 - 0
vector.xcodeproj/project.pbxproj

@@ -248,6 +248,7 @@
 				MTL_ENABLE_DEBUG_INFO = YES;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SDKROOT = macosx;
+				USER_HEADER_SEARCH_PATHS = ..;
 			};
 			name = Debug;
 		};
@@ -284,6 +285,7 @@
 				MTL_ENABLE_DEBUG_INFO = NO;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SDKROOT = macosx;
+				USER_HEADER_SEARCH_PATHS = ..;
 			};
 			name = Release;
 		};