Browse Source

major: several changes including api break
- add psuedo-aggregate ctor for math::vector
- add type deduction guide(s)
- delete explicit copy/move
- use C++17 namespacing

Sam Jaffe 1 year ago
parent
commit
1ae5b6b014

+ 1 - 1
.clang-format

@@ -75,7 +75,7 @@ KeepEmptyLinesAtTheStartOfBlocks: true
 MacroBlockBegin: ''
 MacroBlockEnd:   ''
 MaxEmptyLinesToKeep: 1
-NamespaceIndentation: All
+NamespaceIndentation: None
 ObjCBlockIndentWidth: 2
 ObjCSpaceAfterProperty: false
 ObjCSpaceBeforeProtocolList: true

+ 5 - 1
.gitmodules

@@ -1,3 +1,7 @@
 [submodule "extern/expect"]
-	path = extern/expect
+	path = external/expect
 	url = https://gogs.sjaffe.name/sjjaffe/cpp-expect.git
+[submodule "external/test-helpers"]
+	path = external/test-helpers
+	url = ssh://git@gogs.sjaffe.name:3000/sjjaffe/cpp-test-helpers.git
+	branch = main

+ 0 - 1
extern/expect

@@ -1 +0,0 @@
-Subproject commit f096edddd9d8eb2ba07c2dd7ec385500c0576214

+ 1 - 0
external/expect

@@ -0,0 +1 @@
+Subproject commit ff7cd322bd883b085d383253ceefb27933e6d6cf

+ 1 - 0
external/test-helpers

@@ -0,0 +1 @@
+Subproject commit 2860eea66cd30adf2550f47e710ef7ca443fda5a

+ 9 - 9
include/math/vector/forward.h

@@ -2,14 +2,14 @@
 
 #include <cstdlib>
 
-namespace math { namespace vector {
-  template <typename T, std::size_t N> class vector;
+namespace math::vector {
+template <typename T, std::size_t N> class vector;
 
-  struct {
-  } fill;
-  using fill_t = decltype(fill);
-}}
+struct {
+} fill;
+using fill_t = decltype(fill);
+}
 
-namespace math { namespace matrix {
-  template <typename T, std::size_t R, std::size_t C> class matrix;
-}}
+namespace math::matrix {
+template <typename T, std::size_t R, std::size_t C> class matrix;
+}

+ 12 - 12
include/math/vector/traits.hpp

@@ -1,18 +1,18 @@
 #pragma once
 
-namespace math { namespace vector {
+namespace math::vector {
 
-  template <typename T> struct is_vector {
-    static const constexpr bool value = false;
-  };
+template <typename T> struct is_vector {
+  static const constexpr bool value = false;
+};
 
-  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 is_vector<vector<T, N>> {
+  static const constexpr bool value = true;
+};
 
-  template <typename T, std::size_t R, std::size_t C>
-  struct is_vector<matrix::matrix<T, R, C>> {
-    static const constexpr bool value = true;
-  };
+template <typename T, std::size_t R, std::size_t C>
+struct is_vector<matrix::matrix<T, R, C>> {
+  static const constexpr bool value = true;
+};
 
-}}
+}

+ 206 - 217
include/math/vector/vector.hpp

@@ -45,263 +45,252 @@
   for (std::size_t var = 0; var < end; ++var)
 #define VECTOR_FOR_EACH(var) VECTOR_FOR_EACH_RANGE(var, N)
 
-namespace math { namespace vector {
-
-  template <typename T, std::size_t N> class vector {
-  public:
-    using value_type = T;
-
-  private:
-    using mag_t = decltype(std::sqrt(std::declval<T>()));
-    template <typename M>
-    using mul_t = decltype(std::declval<T>() * std::declval<M>());
-    template <typename M>
-    using div_t = decltype(std::declval<T>() / std::declval<M>());
-
-  public:
-    // Constructors
-    vector() = default;
-
-    vector(std::array<T, N> const & init) {
-      VECTOR_FOR_EACH(i) { _data[i] = init[i]; }
-    }
-
-    vector(vector const & other) { *this = other; }
-
-    vector(vector && other) { *this = std::move(other); }
-
-    // Conversion
-    template <typename T2, std::size_t N2>
-    explicit vector(vector<T2, N2> const & other) {
-      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; }
-    }
+namespace math::vector {
+
+template <typename T, std::size_t N> class vector {
+public:
+  using value_type = T;
+
+private:
+  using mag_t = decltype(std::sqrt(std::declval<T>()));
+  template <typename M>
+  using mul_t = decltype(std::declval<T>() * std::declval<M>());
+  template <typename M>
+  using div_t = decltype(std::declval<T>() / std::declval<M>());
+
+public:
+  // Constructors
+  vector() = default;
+
+  template <typename... Us> vector(T arg0, Us... args) {
+    static_assert(std::is_same_v<std::common_type_t<T, Us...>, T>,
+                  "must be type compatible");
+    static_assert(sizeof...(Us) + 1 == N, "size mismatch");
+    *this = vector(std::array<T, N>{arg0, static_cast<T>(args)...});
+  }
 
-    // Assignment
-    vector & operator=(vector const & other) {
-      VECTOR_FOR_EACH(i) { _data[i] = other[i]; }
-      return *this;
-    }
+  vector(std::array<T, N> const & init) {
+    VECTOR_FOR_EACH(i) { _data[i] = init[i]; }
+  }
 
-    vector & operator=(vector && other) {
-      VECTOR_FOR_EACH(i) { _data[i] = std::move(other._data[i]); }
-      return *this;
+  // Conversion
+  template <typename T2, std::size_t N2>
+  explicit vector(vector<T2, N2> const & other) {
+    VECTOR_FOR_EACH_RANGE(i, std::min(N, N2)) {
+      _data[i] = static_cast<T>(other[i]);
     }
+  }
 
-    // Named Accessors
-    // - Numeric Vector Accessors
-    VECTOR_ACCESS_FN(x, 0)
-    VECTOR_ACCESS_FN(y, 1)
-    VECTOR_ACCESS_FN(z, 2)
-    VECTOR_ACCESS_FN(w, 3)
-
-    // - Color Vector Accessors
-    VECTOR_ACCESS_FN(r, 0)
-    VECTOR_ACCESS_FN(g, 1)
-    VECTOR_ACCESS_FN(b, 2)
-    VECTOR_ACCESS_FN(a, 3)
-
-    // Unnamed Accessors
-    value_type const & operator[](std::size_t idx) const { return _data[idx]; }
+  vector(T const & v, fill_t) {
+    VECTOR_FOR_EACH(i) { _data[i] = v; }
+  }
 
-    value_type & operator[](std::size_t idx) { return _data[idx]; }
+  // Named Accessors
+  // - Numeric Vector Accessors
+  VECTOR_ACCESS_FN(x, 0)
+  VECTOR_ACCESS_FN(y, 1)
+  VECTOR_ACCESS_FN(z, 2)
+  VECTOR_ACCESS_FN(w, 3)
+
+  // - Color Vector Accessors
+  VECTOR_ACCESS_FN(r, 0)
+  VECTOR_ACCESS_FN(g, 1)
+  VECTOR_ACCESS_FN(b, 2)
+  VECTOR_ACCESS_FN(a, 3)
+
+  // Unnamed Accessors
+  constexpr value_type const & operator[](std::size_t idx) const {
+    return _data[idx];
+  }
+  constexpr value_type & operator[](std::size_t idx) { return _data[idx]; }
 
-    value_type const & at(std::size_t idx) const {
-      expects(idx < N, std::out_of_range, "index out of range");
-      return _data[idx];
-    }
+  value_type const & at(std::size_t idx) const {
+    expects(idx < N, std::out_of_range, "index out of range");
+    return _data[idx];
+  }
 
-    value_type & at(std::size_t idx) {
-      expects(idx < N, std::out_of_range, "index out of range");
-      return _data[idx];
-    }
+  value_type & at(std::size_t 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]; }
-      return *this;
-    }
+  // Mathematical Operations
+  vector & operator+=(vector const & other) {
+    VECTOR_FOR_EACH(i) { _data[i] += other[i]; }
+    return *this;
+  }
 
-    vector & operator+=(T const & other) {
-      return operator+=(vector(other, fill));
-    }
+  vector & operator+=(T const & other) {
+    return operator+=(vector(other, fill));
+  }
 
-    vector operator+(vector const & other) const {
-      return vector{*this} += other;
-    }
+  vector operator+(vector const & other) const {
+    return vector{*this} += other;
+  }
 
-    vector operator+(T const & other) const {
-      return operator+(vector(other, fill));
-    }
+  vector operator+(T const & other) const {
+    return operator+(vector(other, fill));
+  }
 
-    friend vector operator+(T const & lhs, vector const & rhs) {
-      return rhs + lhs;
-    }
+  friend vector operator+(T const & lhs, vector const & rhs) {
+    return rhs + lhs;
+  }
 
-    vector & operator-=(vector const & other) {
-      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-=(T const & other) {
-      return operator-=(vector(other, fill));
-    }
+  vector & operator-=(T const & other) {
+    return operator-=(vector(other, fill));
+  }
 
-    vector operator-(vector const & other) const {
-      return vector{*this} -= other;
-    }
+  vector operator-(vector const & other) const {
+    return vector{*this} -= other;
+  }
 
-    vector operator-(T const & other) const {
-      return operator-(vector(other, fill));
-    }
+  vector operator-(T const & other) const {
+    return operator-(vector(other, fill));
+  }
 
-    friend vector operator-(T const & lhs, vector const & rhs) {
-      return vector(lhs, fill) - rhs;
-    }
+  friend vector operator-(T const & lhs, vector const & rhs) {
+    return vector(lhs, fill) - rhs;
+  }
 
-    vector operator-() const { return vector{} -= *this; }
+  vector operator-() const { return vector{} -= *this; }
 
-    template <typename M>
-    VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N) & operator*=(M c) {
-      VECTOR_FOR_EACH(i) { _data[i] *= c; }
-      return *this;
-    }
+  template <typename M>
+  VECTOR_ENABLE_IF_EQ_T(mul_t<M>, T, N) & operator*=(M c) {
+    VECTOR_FOR_EACH(i) { _data[i] *= c; }
+    return *this;
+  }
 
-    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_DISABLE_IF_VECTOR(M, mul_t<M>, N)
+  operator*(M c) const {
+    return vector<mul_t<M>, N>{*this} *= c;
+  }
 
-    template <typename M>
-    friend VECTOR_DISABLE_IF_VECTOR(M, mul_t<M>, N)
-    operator*(M c, vector<T, N> const & v) {
-      return v * c;
-    }
+  template <typename M>
+  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_ENABLE_IF_EQ_T(mul_t<M>, T, N) & operator*=(vector<M, N> c) {
-      VECTOR_FOR_EACH(i) { _data[i] *= c[i]; }
-      return *this;
-    }
+  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;
+  }
 
-    template <typename M>
-    vector<mul_t<M>, N> operator*(vector<M, N> const & other) const {
-      return vector<mul_t<M>, N>{*this} *= other;
-    }
+  template <typename M>
+  vector<mul_t<M>, N> operator*(vector<M, N> const & other) const {
+    return vector<mul_t<M>, N>{*this} *= other;
+  }
 
-    template <typename M>
-    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_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_DISABLE_IF_VECTOR(M, div_t<M>, N)
-    operator/(M c) const {
-      return vector<div_t<M>, N>{*this} /= c;
-    }
+  template <typename M>
+  VECTOR_DISABLE_IF_VECTOR(M, div_t<M>, N)
+  operator/(M c) const {
+    return vector<div_t<M>, N>{*this} /= c;
+  }
 
-    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_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;
-    }
+  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); }
-      return accum;
-    }
+  // Vector Operations
+  value_type dot(vector const & other) const {
+    value_type accum{};
+    VECTOR_FOR_EACH(i) { accum += at(i) * other.at(i); }
+    return accum;
+  }
 
-    mag_t magnitude() const { return std::sqrt(dot(*this)); }
+  mag_t magnitude() const { return std::sqrt(dot(*this)); }
 
-    vector<mag_t, N> unit() const { return *this / magnitude(); }
+  vector<mag_t, N> unit() const { return *this / magnitude(); }
 
-    VECTOR_ENABLE_IF_EQ_N(3, T, N) cross(vector const & other) const {
-      return {{y() * other.z() - z() * other.y(),
-               z() * other.x() - x() * other.z(),
-               x() * other.y() - y() * other.x()}};
-    }
+  VECTOR_ENABLE_IF_EQ_N(3, T, N) cross(vector const & other) const {
+    return {{y() * other.z() - z() * other.y(),
+             z() * other.x() - x() * other.z(),
+             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()}};
-    }
+  VECTOR_ENABLE_IF_EQ_N(2, T, 3) cross(vector const & other) const {
+    return {{0, 0, x() * other.y() - y() * other.x()}};
+  }
 
-    vector<mag_t, N> projection(vector const & other) const {
-      vector<mag_t, N> b_p = other.unit();
-      return b_p * vector<mag_t, N>{*this}.dot(b_p);
-    }
+  vector<mag_t, N> projection(vector const & other) const {
+    vector<mag_t, N> b_p = other.unit();
+    return b_p * vector<mag_t, N>{*this}.dot(b_p);
+  }
 
-  private:
-    value_type _data[N] = {value_type()};
-  };
+private:
+  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, typename... Us>
+vector(T, Us...) -> vector<T, sizeof...(Us) + 1>;
 
-  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>
+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>
-  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>
+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;
   }
-  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;
-  }
-}}
+  return 0;
+}
 
-template <typename... Ts>
-auto make_vector(Ts &&... elems)
-    -> math::vector::vector<typename std::common_type<Ts...>::type,
-                            sizeof...(Ts)> {
-  return {{elems...}};
+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;

+ 52 - 52
test/vector_test.cxx

@@ -5,7 +5,7 @@
 //  Created by Sam Jaffe on 6/2/18.
 //
 
-#include <gmock/gmock.h>
+#include <testing/xcode_gtest_helper.h>
 
 #include "math/vector/vector.hpp"
 
@@ -16,6 +16,7 @@ template <typename T, size_t N> math::vector::vector<T, N> iota() {
   return rval;
 }
 
+using math::vector::vector;
 using vec2i = math::vector::vector<int, 2>;
 using vec3 = math::vector::vector<double, 3>;
 using vec3i = math::vector::vector<int, 3>;
@@ -26,18 +27,18 @@ vec3i iota3i() { return iota<int, 3>(); }
 vec4i iota4i() { return iota<int, 4>(); }
 
 TEST(Vector, Equality) {
-  EXPECT_THAT((iota3i()), vec3i({1, 2, 3}));
-  EXPECT_THAT((iota3i()), ::testing::Ne(vec3i({0, 2, 3})));
+  EXPECT_THAT((iota3i()), vec3i(1, 2, 3));
+  EXPECT_THAT((iota3i()), ::testing::Ne(vec3i(0, 2, 3)));
 }
 
 TEST(Vector, Comparison) {
   vec3i const iota = iota3i();
-  vec3i const low_lt({0, 2, 3});
-  vec3i const mid_lt({1, 1, 3});
-  vec3i const high_lt({1, 2, 2});
-  vec3i const low_gt({2, 2, 3});
-  vec3i const mid_gt({1, 3, 3});
-  vec3i const high_gt({1, 2, 4});
+  vec3i const low_lt{0, 2, 3};
+  vec3i const mid_lt{1, 1, 3};
+  vec3i const high_lt{1, 2, 2};
+  vec3i const low_gt{2, 2, 3};
+  vec3i const mid_gt{1, 3, 3};
+  vec3i const high_gt{1, 2, 4};
   EXPECT_THAT(iota, ::testing::Gt(low_lt));
   EXPECT_THAT(iota, ::testing::Gt(mid_lt));
   EXPECT_THAT(iota, ::testing::Gt(high_lt));
@@ -51,15 +52,15 @@ TEST(Vector, Comparison) {
 }
 
 TEST(Vector, DefaultConstructorIsAllZero) {
-  EXPECT_THAT(vec3i(), vec3i({0, 0, 0}));
+  EXPECT_THAT(vec3i(), vec3i(0, 0, 0));
 }
 
 TEST(Vector, FillConstructorInsertsAllElements) {
-  EXPECT_THAT(vec3i(1, math::vector::fill), vec3i({1, 1, 1}));
+  EXPECT_THAT(vec3i(1, math::vector::fill), vec3i(1, 1, 1));
 }
 
 TEST(Vector, ExtensionConstructorAppendsZeros) {
-  EXPECT_THAT(vec4i(iota3i()), vec4i({1, 2, 3, 0}));
+  EXPECT_THAT(vec4i(iota3i()), vec4i(1, 2, 3, 0));
 }
 
 TEST(Vector, CanAccessVectorElements) {
@@ -90,81 +91,80 @@ TEST(Vector, AccessingOutOfRangeThrows) {
 }
 
 TEST(Vector, CrossProduct2DHasOnlyZElement) {
-  EXPECT_THAT(vec2i({1, 1}).cross(vec2i({-1, 1})), vec3i({0, 0, 2}));
+  EXPECT_THAT(vec2i(1, 1).cross(vec2i(-1, 1)), vec3i(0, 0, 2));
 }
 
 TEST(Vector, CrossProduct3DHasAllElements) {
-  EXPECT_THAT(vec3i({1, 1, 2}).cross(vec3i({-1, 1, 1})), vec3i({-1, -3, 2}));
+  EXPECT_THAT(vec3i(1, 1, 2).cross(vec3i(-1, 1, 1)), vec3i(-1, -3, 2));
 }
 
 TEST(Vector, AdditionIsPiecewise) {
-  EXPECT_THAT((vec2i{{1, 0}} + vec2i{{0, 1}}), vec2i({1, 1}));
+  EXPECT_THAT((vec2i{1, 0} + vec2i{0, 1}), vec2i(1, 1));
 }
 
 TEST(Vector, SubtractionIsPiecewise) {
-  EXPECT_THAT((vec2i{{1, 0}} - vec2i{{0, 1}}), vec2i({1, -1}));
+  EXPECT_THAT((vec2i{1, 0} - vec2i{0, 1}), vec2i(1, -1));
 }
 
 TEST(Vector, MultiplicationIsPiecewise) {
-  EXPECT_THAT((vec2i{{1, 0}} * vec2i({2, 1})), vec2i({2, 0}));
+  EXPECT_THAT((vec2i{1, 0} * vec2i{2, 1}), vec2i(2, 0));
 }
 
 TEST(Vector, DivisionIsPiecewise) {
-  EXPECT_THAT((vec2i{{6, 4}} / vec2i({2, 1})), vec2i({3, 4}));
+  EXPECT_THAT((vec2i{6, 4} / vec2i{2, 1}), vec2i(3, 4));
 }
 
 TEST(Vector, DivisionByZeroThrowsException) {
   EXPECT_THROW(vec3{} / 0, std::domain_error);
-  EXPECT_THROW((vec3{{1.0, 1.0, 1.0}} / vec3({1.0, 0.5, 0.0})),
-               std::domain_error);
+  EXPECT_THROW((vec3{1.0, 1.0, 1.0} / vec3(1.0, 0.5, 0.0)), std::domain_error);
 }
 
 TEST(Vector, AdditionWithValueType) {
-  EXPECT_THAT(vec2i({1, 0}) + 1, vec2i({2, 1}));
-  EXPECT_THAT(1 + iota2i(), vec2i({2, 3}));
+  EXPECT_THAT(vec2i(1, 0) + 1, vec2i(2, 1));
+  EXPECT_THAT(1 + iota2i(), vec2i(2, 3));
 }
 
 TEST(Vector, SubtractionWithValueType) {
-  EXPECT_THAT(4 - iota2i(), vec2i({3, 2}));
-  EXPECT_THAT(vec2i({1, 0}) - 1, vec2i({0, -1}));
+  EXPECT_THAT(4 - iota2i(), vec2i(3, 2));
+  EXPECT_THAT(vec2i(1, 0) - 1, vec2i(0, -1));
 }
 
 TEST(Vector, MultiplicationWithValueType) {
-  EXPECT_THAT((vec2i{{1, 0}} * 3), vec2i({3, 0}));
-  EXPECT_THAT(2 * iota2i(), vec2i({2, 4}));
+  EXPECT_THAT((vec2i{{1, 0}} * 3), vec2i(3, 0));
+  EXPECT_THAT(2 * iota2i(), vec2i(2, 4));
 }
 
 TEST(Vector, DivisionWithValueType) {
-  EXPECT_THAT((vec2i{{6, 4}} / 2), vec2i({3, 2}));
+  EXPECT_THAT((vec2i{{6, 4}} / 2), vec2i(3, 2));
   //  EXPECT_THAT(4/iota2i(), (vec2i{4,2}));
 }
 
 TEST(Vector, OperatorPlusEqualsMutatesValue) {
   vec3i vec = iota3i();
-  EXPECT_THAT(vec += iota3i(), vec3i({2, 4, 6}));
-  EXPECT_THAT(vec, vec3i({2, 4, 6}));
-  EXPECT_THAT(vec += 1, vec3i({3, 5, 7}));
-  EXPECT_THAT(vec, vec3i({3, 5, 7}));
+  EXPECT_THAT(vec += iota3i(), vec3i(2, 4, 6));
+  EXPECT_THAT(vec, vec3i(2, 4, 6));
+  EXPECT_THAT(vec += 1, vec3i(3, 5, 7));
+  EXPECT_THAT(vec, vec3i(3, 5, 7));
 }
 
 TEST(Vector, OperatorMinusEqualsMutatesValue) {
   vec3i vec = iota3i();
-  EXPECT_THAT(vec -= 1, vec3i({0, 1, 2}));
-  EXPECT_THAT(vec, vec3i({0, 1, 2}));
-  EXPECT_THAT(vec -= iota3i(), vec3i({-1, -1, -1}));
-  EXPECT_THAT(vec, vec3i({-1, -1, -1}));
+  EXPECT_THAT(vec -= 1, vec3i(0, 1, 2));
+  EXPECT_THAT(vec, vec3i(0, 1, 2));
+  EXPECT_THAT(vec -= iota3i(), vec3i(-1, -1, -1));
+  EXPECT_THAT(vec, vec3i(-1, -1, -1));
 }
 
 TEST(Vector, MultiplicationWorksAcrossTypes) {
-  EXPECT_THAT(iota3i() * 0.5, vec3({0.5, 1.0, 1.5}));
-  EXPECT_THAT(0.5 * iota3i(), vec3({0.5, 1.0, 1.5}));
-  EXPECT_THAT(vec3({2.0, 1.5, -2}) * iota3i(), vec3({2.0, 3.0, -6.0}));
+  EXPECT_THAT(iota3i() * 0.5, vec3(0.5, 1.0, 1.5));
+  EXPECT_THAT(0.5 * iota3i(), vec3(0.5, 1.0, 1.5));
+  EXPECT_THAT(vec3(2.0, 1.5, -2) * iota3i(), vec3(2.0, 3.0, -6.0));
 }
 
 TEST(Vector, DivisionWorksAcrossTypes) {
-  EXPECT_THAT(iota3i() / 0.5, vec3({2.0, 4.0, 6.0}));
-  EXPECT_THAT(iota3i() / vec3({2.0, 2.5, -2}), vec3({0.5, 0.8, -1.5}));
-  EXPECT_THAT(vec3({2.0, 2.5, -3}) / iota3i(), vec3({2.0, 1.25, -1.0}));
+  EXPECT_THAT(iota3i() / 0.5, vec3(2.0, 4.0, 6.0));
+  EXPECT_THAT(iota3i() / vec3(2.0, 2.5, -2), vec3(0.5, 0.8, -1.5));
+  EXPECT_THAT(vec3(2.0, 2.5, -3) / iota3i(), vec3(2.0, 1.25, -1.0));
 }
 
 TEST(Vector, Length) {
@@ -176,19 +176,19 @@ TEST(Vector, Length) {
 
 TEST(Vector, Distance) {
   //    EXPECT_THAT((iota3i().distanceSquared(vec3i{3, 1, -1})), 21);
-  EXPECT_THAT((iota3i() - vec3i({3, 1, -1})).magnitude(),
+  EXPECT_THAT((iota3i() - vec3i{3, 1, -1}).magnitude(),
               ::testing::DoubleNear(std::sqrt(21),
                                     std::numeric_limits<double>::epsilon()));
 }
 
 TEST(Vector, Projection) {
-  EXPECT_THAT(iota3i().projection(vec3i({3, 1, -1})).magnitude(),
+  EXPECT_THAT(iota3i().projection(vec3i{3, 1, -1}).magnitude(),
               ::testing::DoubleNear(std::sqrt(4.0 / 11.0),
                                     std::numeric_limits<double>::epsilon()));
 }
 
 TEST(Vector, DotProductIsSumOfElementProducts) {
-  EXPECT_THAT(iota3i().dot(vec3i({3, 0, -1})), 0);
+  EXPECT_THAT(iota3i().dot(vec3i{3, 0, -1}), 0);
 }
 
 TEST(Vector, UnitFunctionCreatesNewVectorOverMagnitude) {
@@ -203,7 +203,7 @@ TEST(Vector, UnitFunctionCreatesNewVectorOverMagnitude) {
 }
 
 TEST(Vector, CanCastEntireVectorThroughConstructor) {
-  EXPECT_THAT(vec3i(vec3({1.0, 2.3, 3.9})), iota3i());
+  EXPECT_THAT(vec3i(vec3{1.0, 2.3, 3.9}), iota3i());
 }
 
 TEST(Vector, SwapExchangesAllValues) {
@@ -218,17 +218,17 @@ TEST(Vector, SwapExchangesAllValues) {
 }
 
 TEST(Vector, UnaryNegateOperatorNegatesAllElements) {
-  EXPECT_THAT(-iota3i(), vec3i({-1, -2, -3}));
+  EXPECT_THAT(-iota3i(), vec3i(-1, -2, -3));
 }
 
 TEST(Vector, AbsoluteValueOfVectorAbsAllElements) {
   EXPECT_THAT(iota3i(), abs(-iota3i()));
 }
 
-TEST(Vector, MakeVectorAllowsConstuctionFromVariadicComponents) {
-  EXPECT_TRUE((std::is_same<vec2i, decltype(make_vector(1, 2))>::value));
-  EXPECT_THAT(iota2i(), make_vector(1, 2));
-  EXPECT_FALSE((std::is_same<vec2i, decltype(make_vector(1, 2, 3))>::value));
-  EXPECT_TRUE((std::is_same<vec3i, decltype(make_vector(1, 2, 3))>::value));
-  EXPECT_THAT(iota3i(), make_vector(1, 2, 3));
+TEST(Vector, CanPerformTypeDeduced) {
+  EXPECT_TRUE((std::is_same<vec2i, decltype(vector{1, 2})>::value));
+  EXPECT_THAT(iota2i(), vector(1, 2));
+  EXPECT_FALSE((std::is_same<vec2i, decltype(vector{1, 2, 3})>::value));
+  EXPECT_TRUE((std::is_same<vec3i, decltype(vector{1, 2, 3})>::value));
+  EXPECT_THAT(iota3i(), vector(1, 2, 3));
 }

+ 80 - 30
vector.xcodeproj/project.pbxproj

@@ -41,27 +41,48 @@
 			remoteGlobalIDString = 05818F901A685AEA0072A469;
 			remoteInfo = GoogleMockTests;
 		};
-		CDAE625F2B77B93600551FB8 /* PBXContainerItemProxy */ = {
+		CDAE63E12B77D9C000551FB8 /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = CDAE62592B77B93600551FB8 /* expect.xcodeproj */;
 			proxyType = 2;
-			remoteGlobalIDString = CDD476BD29C5423B00BDB829;
-			remoteInfo = expect;
+			remoteGlobalIDString = CDEC1E8A235248390091D9F2;
+			remoteInfo = "expect-test";
 		};
-		CDAE62612B77B93600551FB8 /* PBXContainerItemProxy */ = {
+		CDAE63E92B77D9FF00551FB8 /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
-			containerPortal = CDAE62592B77B93600551FB8 /* expect.xcodeproj */;
+			containerPortal = CDAE63E32B77D9FF00551FB8 /* test-helpers.xcodeproj */;
 			proxyType = 2;
-			remoteGlobalIDString = CDEC1E8A235248390091D9F2;
-			remoteInfo = "expect-test";
+			remoteGlobalIDString = CD6030FC2AF67772000D9F31;
+			remoteInfo = "test-helpers";
 		};
-		CDAE62632B77B94100551FB8 /* PBXContainerItemProxy */ = {
+		CDAE63EB2B77D9FF00551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE63E32B77D9FF00551FB8 /* test-helpers.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CDD965FA2B654D090091D92C;
+			remoteInfo = "test-helpers-test";
+		};
+		CDAE63ED2B77DA1B00551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE63E32B77D9FF00551FB8 /* test-helpers.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = CD6030FB2AF67772000D9F31;
+			remoteInfo = "test-helpers";
+		};
+		CDC7D1CB2B77DA6F0034C06F /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = CDAE62592B77B93600551FB8 /* expect.xcodeproj */;
 			proxyType = 1;
 			remoteGlobalIDString = CDD476BC29C5423B00BDB829;
 			remoteInfo = expect;
 		};
+		CDC7D1CF2B77DA6F0034C06F /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE62592B77B93600551FB8 /* expect.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CDD476BD29C5423B00BDB829;
+			remoteInfo = expect;
+		};
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
@@ -71,7 +92,8 @@
 		CD10425C24E837FB00C0DF2A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		CD10426824E8701100C0DF2A /* math */ = {isa = PBXFileReference; lastKnownFileType = folder; name = math; path = include/math; sourceTree = "<group>"; };
 		CDAE62452B77B8A800551FB8 /* libvector.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libvector.a; sourceTree = BUILT_PRODUCTS_DIR; };
-		CDAE62592B77B93600551FB8 /* expect.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = expect.xcodeproj; path = ../expect/expect.xcodeproj; sourceTree = "<group>"; };
+		CDAE62592B77B93600551FB8 /* expect.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = expect.xcodeproj; path = extern/expect/expect.xcodeproj; sourceTree = "<group>"; };
+		CDAE63E32B77D9FF00551FB8 /* test-helpers.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "test-helpers.xcodeproj"; path = "extern/test-helpers/test-helpers.xcodeproj"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -97,6 +119,7 @@
 			isa = PBXGroup;
 			children = (
 				CDAE62592B77B93600551FB8 /* expect.xcodeproj */,
+				CDAE63E32B77D9FF00551FB8 /* test-helpers.xcodeproj */,
 				CD0C597A20C31CC300454F82 /* GoogleMock.xcodeproj */,
 				CD10426824E8701100C0DF2A /* math */,
 				CD10423524E836A700C0DF2A /* test */,
@@ -149,11 +172,20 @@
 			name = Frameworks;
 			sourceTree = "<group>";
 		};
-		CDAE625A2B77B93600551FB8 /* Products */ = {
+		CDAE63DE2B77D9C000551FB8 /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				CDAE62602B77B93600551FB8 /* libexpect.a */,
-				CDAE62622B77B93600551FB8 /* expect-test.xctest */,
+				CDC7D1D02B77DA6F0034C06F /* libexpect.a */,
+				CDAE63E22B77D9C000551FB8 /* expect-test.xctest */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		CDAE63E42B77D9FF00551FB8 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				CDAE63EA2B77D9FF00551FB8 /* libtest-helpers.a */,
+				CDAE63EC2B77D9FF00551FB8 /* test-helpers-test.xctest */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -182,6 +214,7 @@
 			buildRules = (
 			);
 			dependencies = (
+				CDAE63EE2B77DA1B00551FB8 /* PBXTargetDependency */,
 			);
 			name = "vector-test";
 			productName = "vector-test";
@@ -200,7 +233,7 @@
 			buildRules = (
 			);
 			dependencies = (
-				CDAE62642B77B94100551FB8 /* PBXTargetDependency */,
+				CDC7D1CC2B77DA6F0034C06F /* PBXTargetDependency */,
 			);
 			name = vector;
 			productName = vector;
@@ -238,13 +271,17 @@
 			projectDirPath = "";
 			projectReferences = (
 				{
-					ProductGroup = CDAE625A2B77B93600551FB8 /* Products */;
+					ProductGroup = CDAE63DE2B77D9C000551FB8 /* Products */;
 					ProjectRef = CDAE62592B77B93600551FB8 /* expect.xcodeproj */;
 				},
 				{
 					ProductGroup = CD0C597B20C31CC300454F82 /* Products */;
 					ProjectRef = CD0C597A20C31CC300454F82 /* GoogleMock.xcodeproj */;
 				},
+				{
+					ProductGroup = CDAE63E42B77D9FF00551FB8 /* Products */;
+					ProjectRef = CDAE63E32B77D9FF00551FB8 /* test-helpers.xcodeproj */;
+				},
 			);
 			projectRoot = "";
 			targets = (
@@ -283,18 +320,32 @@
 			remoteRef = CD0C598720C31CC300454F82 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
-		CDAE62602B77B93600551FB8 /* libexpect.a */ = {
+		CDAE63E22B77D9C000551FB8 /* expect-test.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = "expect-test.xctest";
+			remoteRef = CDAE63E12B77D9C000551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDAE63EA2B77D9FF00551FB8 /* libtest-helpers.a */ = {
 			isa = PBXReferenceProxy;
 			fileType = archive.ar;
-			path = libexpect.a;
-			remoteRef = CDAE625F2B77B93600551FB8 /* PBXContainerItemProxy */;
+			path = "libtest-helpers.a";
+			remoteRef = CDAE63E92B77D9FF00551FB8 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
-		CDAE62622B77B93600551FB8 /* expect-test.xctest */ = {
+		CDAE63EC2B77D9FF00551FB8 /* test-helpers-test.xctest */ = {
 			isa = PBXReferenceProxy;
 			fileType = wrapper.cfbundle;
-			path = "expect-test.xctest";
-			remoteRef = CDAE62612B77B93600551FB8 /* PBXContainerItemProxy */;
+			path = "test-helpers-test.xctest";
+			remoteRef = CDAE63EB2B77D9FF00551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDC7D1D02B77DA6F0034C06F /* libexpect.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libexpect.a;
+			remoteRef = CDC7D1CF2B77DA6F0034C06F /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
 /* End PBXReferenceProxy section */
@@ -349,10 +400,15 @@
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
-		CDAE62642B77B94100551FB8 /* PBXTargetDependency */ = {
+		CDAE63EE2B77DA1B00551FB8 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = "test-helpers";
+			targetProxy = CDAE63ED2B77DA1B00551FB8 /* PBXContainerItemProxy */;
+		};
+		CDC7D1CC2B77DA6F0034C06F /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			name = expect;
-			targetProxy = CDAE62632B77B94100551FB8 /* PBXContainerItemProxy */;
+			targetProxy = CDC7D1CB2B77DA6F0034C06F /* PBXContainerItemProxy */;
 		};
 /* End PBXTargetDependency section */
 
@@ -361,6 +417,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
 				CLANG_WARN_COMMA = YES;
@@ -401,6 +458,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
 				CLANG_WARN_COMMA = YES;
@@ -441,7 +499,6 @@
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
@@ -453,7 +510,6 @@
 				CODE_SIGN_STYLE = Automatic;
 				COMBINE_HIDPI_IMAGES = YES;
 				DEBUG_INFORMATION_FORMAT = dwarf;
-				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_PREPROCESSOR_DEFINITIONS = (
@@ -478,7 +534,6 @@
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
@@ -492,7 +547,6 @@
 				COPY_PHASE_STRIP = NO;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				ENABLE_NS_ASSERTIONS = NO;
-				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				INFOPLIST_FILE = "vector-test/Info.plist";
@@ -511,7 +565,6 @@
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CLANG_ENABLE_OBJC_WEAK = YES;
@@ -522,7 +575,6 @@
 				CODE_SIGN_STYLE = Automatic;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				EXECUTABLE_PREFIX = lib;
-				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_PREPROCESSOR_DEFINITIONS = (
@@ -545,7 +597,6 @@
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CLANG_ENABLE_OBJC_WEAK = YES;
@@ -558,7 +609,6 @@
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				ENABLE_NS_ASSERTIONS = NO;
 				EXECUTABLE_PREFIX = lib;
-				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				MACOSX_DEPLOYMENT_TARGET = 12.3;