#include <initializer_list>

using std::initializer_list;

namespace _3D
{
  template<typename T>
  struct Vector3D {
    T x, y, z;

    Vector3D()
    {
      this->zero();
    }
    Vector3D(T xInit, T yInit, T zInit) : x(xInit), y(yInit), z(zInit)
    {}
    Vector3D(initializer_list<T> coordinates)
    {
      auto it = coordinates.begin();

      x = *(it++);
      y = *(it++);
      z = *it;
    }
    template <typename U>
    Vector3D(const Vector3D<U>& vec) : x(static_cast<T>(vec.x)), y(static_cast<T>(vec.y)), z(static_cast<T>(vec.z))
    {}

    Vector3D<T> &operator+=(const Vector3D<T> &vec) noexcept
    {
      x += vec.x;
      y += vec.y;
      z += vec.z;

      return *this;
    }
    Vector3D<T> &operator-=(const Vector3D<T> &vec) noexcept
    {
      x -= vec.x;
      y -= vec.y;
      z -= vec.z;

      return *this;
    }
    Vector3D<T> &operator*=(const Vector3D<T> &vec) noexcept
    {
      x *= vec.x;
      y *= vec.y;
      z *= vec.z;

      return *this;
    }
    Vector3D<T> &operator/=(const Vector3D<T> &vec) noexcept
    {
      x /= vec.x;
      y /= vec.y;
      z /= vec.z;

      return *this;
    }

    Vector3D<T> operator*(const T &i) noexcept
    {
      return Vector2D<T>(x * i, y * i, z * i);
    }
    Vector3D<T> operator/(const T &i) noexcept
    {
      return Vector2D<T>(x / i, y / i, z / i);
    }
    Vector3D<T> &zero() noexcept
    {
      x = static_cast<T>(0);
      y = static_cast<T>(0);
      z = static_cast<T>(0);

      return *this;
    }
  };

  template<typename T>
  Vector3D<T> operator+(const Vector3D<T> &v1, const Vector3D<T> &v2)
  {
    return Vector3D<T>(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
  }
  template<typename T>
  Vector3D<T> operator-(const Vector3D<T> &v1, const Vector3D<T> &v2)
  {
    return Vector3D<T>(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
  }
  template<typename T>
  Vector3D<T> operator*(const Vector3D<T> &v1, const Vector3D<T> &v2)
  {
    return Vector3D<T>(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
  }
  template<typename T>
  Vector3D<T> operator/(const Vector3D<T> &v1, const Vector3D<T> &v2)
  {
    return Vector3D<T>(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z);
  }
}