	#include <iostream>
	
	template<typename T, size_t D>
	struct VectorBase;
	
	template<typename T>
	struct VectorBase<T, 2>
	{
		constexpr VectorBase() : v{} {}
		union {
			T v[2];
			struct { T x, y; };
		};
	};
	
	template<typename T>
	struct VectorBase<T, 3>
	{
		constexpr VectorBase() : v{} {}
		union {
			T v[3];
			struct { T x, y, z; };
		};
	};
	
	template<typename T>
	struct VectorBase<T, 4>
	{
		constexpr VectorBase() : v{} {}
		union {
			T v[4];
			struct { T x, y, z, w; };
		};
	};
	
	template<typename T, size_t D>
	struct Vector : public VectorBase<T, D>
	{
		using VectorBase<T, D>::v;
		using size_type = decltype(D);
		using value_type = T;
	
		constexpr Vector() : VectorBase<T,D>{} {}
		constexpr Vector(T scalar) {
			std::fill(std::begin(v), std::end(v), scalar);
		}
		
		constexpr T& operator[](size_type i) const noexcept { return v[i]; }
		constexpr const T& operator[](size_type i) noexcept { return v[i]; }
		
		constexpr size_type size() const noexcept { return D; }
		
		constexpr T* data() noexcept { return &v[0]; }
		constexpr const T* data() const noexcept { return &v[0]; }
	};
	
    template<typename T>
    using Vector2 = Vector<T, 2>;
    template<typename T>
    using Vector3 = Vector<T, 3>;
    template<typename T>
    using Vector4 = Vector<T, 4>;
	
	int main() {
		Vector3<int> v{1};
		
		std::cout << v[0] << ", " << v.z << "\n";
		return 0;
	}

