Last active
February 26, 2021 19:09
-
-
Save znnahiyan/5423cad65c5541a0a1ee9b959419d979 to your computer and use it in GitHub Desktop.
Standalone C++20 3D vectors class (templated and with arithmetic operations defined)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include "Vec3.hpp" | |
int main() { | |
Vec3<int> first = {1, 2, 3}; | |
Vec3<int> second = first + 2; | |
Vec3<double> third = first + 1.5; | |
Vec3<double> fourth = 2.5 + first; | |
Vec3<double> fifth = {1.0, 2.0, 3.0}; | |
cout << first << endl; | |
cout << second << endl; | |
cout << third << endl; | |
cout << fourth << endl; | |
cout << fifth << endl; | |
cout << fourth + fifth << endl; | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef VEC3_HPP | |
#define VEC3_HPP | |
#include <iostream> | |
#include <numbers> // C++20 | |
#include <concepts> // C++20 | |
#include <type_traits> | |
#include <tuple> // C++14 | |
// Concepts for making sure numeric promotion works: int*float -> float, etc. | |
// WARNING: The static check (std::is_Arithmetic<...>) only matches fundamental types (e.g. int, float), | |
// but not actually std::complex or any other type which implements the operations: +, -, *, /. | |
template <typename T> | |
concept Arithmetic = std::is_arithmetic<T>::value; | |
// Concept to ensure that elements can be printed. | |
template <typename T, typename _Elem = char, typename _Traits = std::char_traits<char>> | |
concept Printable = requires (std::basic_ostream<_Elem, _Traits>& os, T a) { | |
os << a; | |
}; | |
template <typename T = double> requires Arithmetic<T> && Printable<T> | |
struct Vec3 { | |
T x, y, z; | |
// Use special member functions to autogenerate copy ctor, move ctor, copy =, and move =. | |
Vec3() = default; | |
template <Arithmetic U> Vec3(U x, U y, U z) : x(x), y(y), z(z) {} | |
template <Arithmetic U> Vec3(const Vec3<U>& rhs) : x(rhs.x), y(rhs.y), z(rhs.z) {} | |
// Vector Arithmetic. | |
template <Arithmetic U> Vec3<T>& operator+=(const Vec3<U>& rhs) { x += rhs.x; y += rhs.y; z += rhs.z; return *this; } | |
template <Arithmetic U> Vec3<T>& operator-=(const Vec3<U>& rhs) { x -= rhs.x; y -= rhs.y; z -= rhs.z; return *this; } | |
template <Arithmetic U> Vec3<decltype((T()+U()))> operator+(const Vec3<U>& rhs) const { return static_cast<Vec3<decltype((T()+U()))>>(*this) += rhs; } | |
template <Arithmetic U> Vec3<decltype((T()-U()))> operator-(const Vec3<U>& rhs) const { return static_cast<Vec3<decltype((T()-U()))>>(*this) -= rhs; } | |
// Scalar Arithmetic. NOTE: Allows broadcasting from scalars to vectors for + and -. | |
template <Arithmetic U> Vec3<T>& operator+=(const U& rhs) { x += rhs; y += rhs; z += rhs; return *this; } | |
template <Arithmetic U> Vec3<T>& operator-=(const U& rhs) { x -= rhs; y -= rhs; z -= rhs; return *this; } | |
template <Arithmetic U> Vec3<T>& operator*=(const U& rhs) { x *= rhs; y *= rhs; z *= rhs; return *this; } | |
template <Arithmetic U> Vec3<T>& operator/=(const U& rhs) { x /= rhs; y /= rhs; z /= rhs; return *this; } | |
// Comparison. | |
template <Arithmetic U> | |
bool operator==(const Vec3<U>& rhs) const { | |
return std::tie(x, y, z) == std::tie(rhs.x, rhs.y, rhs.z); | |
}; | |
// Inner product. | |
template <Arithmetic U> | |
decltype((T()*U()+T()*U()+T()*U())) operator*(const Vec3<U>& rhs) const { | |
return x*rhs.x + y*rhs.y + z*rhs.z; | |
} | |
// Outer product. (Not implemented) | |
template <Arithmetic U> | |
void operator^(const Vec3<U>& rhs) = delete; | |
// Norm. | |
decltype((std::sqrt(T()*T()+T()*T()+T()*T()))) norm() const { return std::sqrt(this->operator*(*this)); } | |
// Printing. | |
friend std::ostream& operator<<(std::ostream& os, const Vec3<T>& vec) { | |
return os << "Vec3<" << typeid(T).name() << ">(x=" << vec.x << ", y=" << vec.y << ", z=" << vec.z << ')'; | |
} | |
}; | |
template <Arithmetic T, Arithmetic U> Vec3<decltype((T()+U()))> operator+(const Vec3<T>& lhs, const U& rhs) { return static_cast<Vec3<decltype((T()+U()))>>(lhs) += rhs; } | |
template <Arithmetic T, Arithmetic U> Vec3<decltype((T()-U()))> operator-(const Vec3<T>& lhs, const U& rhs) { return static_cast<Vec3<decltype((T()-U()))>>(lhs) -= rhs; } | |
template <Arithmetic T, Arithmetic U> Vec3<decltype((T()*U()))> operator*(const Vec3<T>& lhs, const U& rhs) { return static_cast<Vec3<decltype((T()*U()))>>(lhs) *= rhs; } | |
template <Arithmetic T, Arithmetic U> Vec3<decltype((T()/U()))> operator/(const Vec3<T>& lhs, const U& rhs) { return static_cast<Vec3<decltype((T()/U()))>>(lhs) /= rhs; } | |
template <Arithmetic T, Arithmetic U> Vec3<decltype((T()+U()))> operator+(const U& lhs, const Vec3<T>& rhs) { return rhs + lhs; } | |
template <Arithmetic T, Arithmetic U> Vec3<decltype((T()-U()))> operator-(const U& lhs, const Vec3<T>& rhs) { return rhs - lhs; } | |
template <Arithmetic T, Arithmetic U> Vec3<decltype((T()*U()))> operator*(const U& lhs, const Vec3<T>& rhs) { return rhs * lhs; } | |
template <Arithmetic T, Arithmetic U> Vec3<decltype((T()/U()))> operator/(const U& lhs, const Vec3<T>& rhs) { return rhs / lhs; } | |
#endif // VEC3_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment