template class vec_t { template void load_from_args(void) { static_assert(index < N + 1, "too many elements in the initializer"); static_assert(index > N - 1, "too few elements in the initializer"); } template void load_from_args(T first, U... rest) { v[index] = first; load_from_args(rest...); } public: T v[N]; // Basic operations vec_t() = default; template vec_t(T first, U... rest) { load_from_args<0>(first, rest...); } template vec_t(vec_t b) { for (size_t i = 0; i < N; i++) v[i] = (T)b[i]; } T& operator[](size_t i) { return v[i]; } const T& operator[](size_t i) const { return v[i]; } // Comparison friend bool operator==(const vec_t &a, const vec_t &b) { for (size_t i = 0; i < N; i++) if (a[i] != b[i]) return false; return true; } // Good enough for maps or sets. friend bool operator<(const vec_t &a, const vec_t &b) { for (size_t i = 0; i < N; i++) { if (a[i] < b[i]) return true; else if (a[i] > b[i]) return false; } return false; } // Arithmetics friend vec_t operator+(const vec_t &v) { return v; } friend vec_t operator+(const vec_t &a, const vec_t &b) { vec_t r; for (size_t i = 0; i < N; i++) r[i] = a[i] + b[i]; return r; } friend vec_t &operator+=(vec_t &v, const vec_t &b) { for (size_t i = 0; i < N; i++) v[i] += b[i]; return v; } friend vec_t operator-(const vec_t &v) { return -1 * v; } friend vec_t operator-(const vec_t &a, const vec_t &b) { vec_t r; for (size_t i = 0; i < N; i++) r[i] = a[i] - b[i]; return r; } friend vec_t &operator-=(vec_t &v, const vec_t &b) { for (size_t i = 0; i < N; i++) v[i] -= b[i]; return v; } friend T operator*(const vec_t &a, const vec_t &b) { T r = (T)0; for (size_t i = 0; i < N; i++) r += a[i] * b[i]; return r; } friend vec_t operator*(const vec_t &a, const T &b) { vec_t r; for (size_t i = 0; i < N; i++) r[i] = a[i] * b; return r; } friend vec_t operator*(const T &b, const vec_t &a) { return a * b; } friend vec_t &operator*=(vec_t &v, const T &b) { for (size_t i = 0; i < N; i++) v[i] *= b; return v; } friend vec_t operator/(const vec_t &a, const T &b) { vec_t r; for (size_t i = 0; i < N; i++) r[i] = a[i] / b; return r; } friend vec_t operator/(const T &b, const vec_t &a) { return a / b; } friend vec_t &operator/=(vec_t &v, const T &b) { for (size_t i = 0; i < N; i++) v[i] /= b; return v; } // Compatibility with SFML template operator sf::Vector2() const { static_assert(N == 2, "conversion of vec_t with N != 2 to sf::Vector2"); return sf::Vector2((U)v[0], (U)v[1]); } template vec_t(sf::Vector2 b) { static_assert(N == 2, "conversion of sf::Vector2 to vec_t with N != 2"); v[0] = b.x; v[1] = b.y; } // Compatibility with iostream friend std::ostream& operator<<(std::ostream& stream, vec_t v) { stream << "("; for (size_t i = 0; i < N; i++) { if (i) stream << ", "; stream << v.v[i]; } stream << ")"; return stream; } }; // Shorthands typedef vec_t v2f_t; typedef vec_t v2d_t; template class rect_t { public: vec_t a, b; rect_t() = default; rect_t(vec_t a_, vec_t b_) { a = a_; b = b_; } friend std::ostream& operator<<(std::ostream& stream, rect_t r) { stream << "(" << r.a << ", " << r.b << ")"; return stream; } };