C++实现一个带溢出检测的数值类

export module number;

import<concepts>;
import<exception>;
import<vector>;
import<initializer_list>;
import<string>;
import<limits>;
import<format>;
import<algorithm>;
import<cmath>;
import<type_traits>;
import<typeinfo>;

export namespace myNum {

	//Custom numeric overflow exception
	struct NumOverflow :std::exception
	{
		NumOverflow(const std::string& s) :exception(s.data()) {}
	};

	//Specifies that constraints can only be integer and floating point
	template < class T >
	concept number = std::is_arithmetic_v<T>;

	template<number T>
	class Number {
	public:

		constexpr static T max = std::numeric_limits<T>::max();

		constexpr static T min = std::numeric_limits<T>::min();

		constexpr Number(T v)noexcept :_value{ v } {}

		constexpr Number()noexcept = default;

		constexpr Number(Number&& v)noexcept {
			this->_value = v.GetValue();
		}

		constexpr Number(const Number& v)noexcept = default;

		~Number() = default;

		template<typename T2>
		constexpr Number<T>& operator =(const Number<T2>& v)noexcept {
			this->_value = v.GetValue();
			return *this;
		}

		constexpr Number& operator=(const Number& v)noexcept = default;

		template<typename T2>
		constexpr Number<T>& operator =(Number<T2>&& v)noexcept {
			this->_value = v.GetValue();
			return *this;
		}

		constexpr Number& operator++()noexcept
		{
			this->_value++;
			return *this;
		}

		constexpr Number operator++(int)noexcept
		{
			auto old = *this;
			operator++();
			return old;
		}

		constexpr Number& operator--()noexcept
		{
			this->_value--;
			return *this;
		}

		constexpr Number operator--(int)noexcept
		{
			auto old = *this;
			operator--();
			return old;
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator +(const Number<T2>& v)const {
			using Type = std::common_type_t<T, T2>;
			auto max = std::max(static_cast<Type>(this->_value), static_cast<Type>(v.GetValue()));
			if (std::fabs(this->_value + v.GetValue()) < std::fabs(max)) {
				throw NumOverflow(std::format("{} + {} is greater than the maximum value of type {} {}.\nnumerical overflow error.",
					this->_value, v.GetValue(), typeid(Type).name(), std::numeric_limits<Type>::max()));
			}
			else {
				return Number<Type>(this->_value + v.GetValue());
			}
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator +(const T2 v)const {
			using Type = std::common_type_t<T, T2>;
			auto max = std::max(static_cast<Type>(this->_value), static_cast<Type>(v));
			if (std::fabs(this->_value) + std::fabs(v) < max) {
				throw NumOverflow(std::format("{} + {} is greater than the maximum value of type {} {}.\nnumerical overflow error.",
					this->_value, v, typeid(Type).name(), std::numeric_limits<Type>::max()));
			}
			else {
				return Number<Type>(this->_value + v);
			}
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator -(const Number<T2>& v)const noexcept {
			using Type = std::common_type_t<T, T2>;
			if constexpr (std::is_signed_v<Type>) {
				operator-();
				return Number<Type>(this->_value + (-v.GetValue()));
			}
			else {
				return Number<Type>(this->_value -v.GetValue());
			}
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator -(const T2 v)const noexcept {
			using Type = std::common_type_t<T, T2>;
			if constexpr (std::is_signed_v<Type>) {
				operator-();
				return Number<Type>(this->_value + (-v));
			}
			else {
				return Number<Type>(this->_value - v);
			}
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator *(const Number<T2>& v)const {
			int64_t max = this->_value * v.GetValue();
			if (this->_value!=0 && max / this->_value!=v.GetValue()) {
				throw NumOverflow(std::format("{} * {} is greater than the maximum value of type {} {}.\nNumerical overflow error.",
					this->_value, v.GetValue(), typeid(T).name(), std::numeric_limits<T>::max()));
			}
			else {
				return Number<std::common_type_t<T, T2>>(this->_value * v.GetValue());
			}
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator *(const T2 v)const {
			int64_t max = this->_value * v;
			if (this->_value != 0 && max / this->_value != v) {
				throw NumOverflow(std::format("{} * {} is greater than the maximum value of type {} {}.\nNumerical overflow error.",
					this->_value, v, typeid(T).name(), std::numeric_limits<T>::max()));
			}
			else {
				return Number<std::common_type_t<T, T2>>(this->_value * v);
			}
		}

		template<typename T2>
		[[nodiscard]]  Number<std::common_type_t<T, T2>> operator /(const Number<T2>& v)const {
			if (v.GetValue() == -1) 
				throw NumOverflow("Division with a denominator of -1 will result in overflow");
			return Number<std::common_type_t<T, T2>>(this->_value / v.GetValue());
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator /(const T2 v)const {
			if (v == -1)
				throw NumOverflow("Division with a denominator of -1 will result in overflow");
			return Number<std::common_type_t<T, T2>>(this->_value / v);
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator %(const Number<T2>& v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value % v.GetValue());
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator %(const T2 v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value % v);
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator ^(const Number<T2>& v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value ^ v.GetValue());
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator ^(const T2 v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value ^ v);
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator &(const T2 v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value & v);
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator &(const Number<T2>& v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value & v.GetValue());
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator |(const T2 v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value | v);
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator |(const Number<T2>& v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value | v.GetValue());
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator <<(const T2 v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value << v);
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator <<(const Number<T2>& v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value << v.GetValue());
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator >>(const T2 v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value >> v);
		}

		template<typename T2>
		[[nodiscard]] constexpr Number<std::common_type_t<T, T2>> operator >>(const Number<T2>& v)const noexcept {
			return Number<std::common_type_t<T, T2>>(this->_value >> v.GetValue());
		}

		[[nodiscard]] constexpr Number<T> operator ~()const noexcept {
			return Number(~this->_value);
		}

		[[nodiscard]] constexpr bool operator !()const noexcept {
			return !bool(*this);
		}

		
		[[nodiscard]] constexpr Number operator -()const noexcept  {
			static_assert(std::is_signed_v<T>,"Unsigned Number cannot call unary operator -");
			if (this->_value == std::numeric_limits<T>::min())
				throw NumOverflow("operator - Overflow");
			return Number( - this->_value);
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator ==(const Number<T2>& v)const noexcept {
			return this->_value == v.GetValue();
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator ==(const T2& v)const noexcept {
			return this->_value == v;
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator !=(const Number<T2>& v)const noexcept {
			return !this->operator==(v);
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator !=(const T2& v)const noexcept {
			return !this->operator==(v);
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator <(const Number<T2>& v)const noexcept {
			return this->_value < v.GetValue();
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator <(const T2 v)const noexcept {
			return this->_value < v;
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator >(const Number<T2>& v)const noexcept {
			return !this->operator<(v);
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator >(const T2 v)const noexcept {
			return !this->operator<(v);
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator <=(const Number<T2>& v)const noexcept {
			return this->operator<(v) || this->operator==(v);
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator <=(const T2 v)const noexcept {
			return this->operator<(v) || this->operator==(v);
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator >=(const Number<T2>& v)const noexcept {
			return this->operator>(v) || this->operator==(v);
		}

		template<typename T2>
		[[nodiscard]] constexpr bool operator >=(const T2 v)const noexcept {
			return this->operator>(v) || this->operator==(v);
		}

		template<typename T2>
		constexpr void operator+=(const Number<T2>& v)noexcept {
			auto max = std::max(this->_value, static_cast<T>(v.GetValue()));
			if (this->_value + v.GetValue() < max) {
				throw NumOverflow(std::format("{} + {} is greater than the maximum value of type {} {}.\nNumerical overflow error.",
					this->_value, v.GetValue(), typeid(T).name(), std::numeric_limits<T>::max()));
			}
			else {
				this->operator+(v.GetValue());
				this->_value += v.GetValue();
			}
		}

		template<typename T2>
		constexpr void operator+=(Number<T2>&& v) {
			auto max = std::max(this->_value, T(v));
			if (this->_value + v.GetValue() < max) {
				throw NumOverflow(std::format("{} + {} is greater than the maximum value of type {} {}.\nNumerical overflow error.",
					this->_value, v.GetValue(), typeid(T).name(), std::numeric_limits<T>::max()));
			}
			else {
				this->operator+(v.GetValue());
				this->_value += v.GetValue();
			}
		}

		template<typename T2>
		constexpr void operator-=(const Number<T2>& v)noexcept {
			this->_value -= v.GetValue();
		}
		template<typename T2>
		constexpr void operator-=(Number<T2>&& v)noexcept {
			this->_value -= v.GetValue();
		}

		explicit constexpr operator T()const noexcept {
			return this->_value;
		}

		[[nodiscard]] constexpr Number* operator&()noexcept {
			return this;
		}

		explicit constexpr operator bool()const noexcept {
			return static_cast<bool>(this->_value);
		}

		template<typename T>
		auto operator<=>(const T& v)const noexcept {
			return this->_value <=> v;
		}

		[[nodiscard]] constexpr T GetValue()const noexcept {
			return this->_value;
		}

		[[nodiscard]] constexpr std::string to_string()const noexcept {
			return std::format("Number<{}>::_value is {}", typeid(T).name(), this->_value);
		}

	private:
		T _value{};
	};

	//Custom "number" literal
	auto operator "" _num(unsigned long long int lit)noexcept ->decltype(Number(lit))
	{
		return Number(lit);
	};

	auto operator "" _num(long double lit)noexcept ->decltype(Number(lit))
	{
		return Number(lit);
	};

	auto operator "" _num(char lit)noexcept ->decltype(Number(lit))
	{
		return Number(lit);
	};

	auto operator "" _num(wchar_t lit)noexcept->decltype(Number(lit))
	{
		return Number(lit);
	};

	auto operator "" _num(char16_t lit)noexcept ->decltype(Number(lit))
	{
		return Number(lit);
	};

	auto operator "" _num(char32_t lit)noexcept ->decltype(Number(lit))
	{
		return Number(lit);
	};

	//Output operator overloading
	template<number T>
	std::ostream& operator<<(std::ostream& out, Number<T>& v)noexcept {
		out << v.GetValue();
		return out;
	}
	template<number T>
	std::ostream& operator<<(std::ostream& out, Number<T>&& v)noexcept {
		out << v.GetValue();
		return out;
	}

	template<typename T,typename T2>
	auto operator<=>(const Number<T>& v1, const Number<T2>& v2)noexcept {
		return v1.GetValue() <=> v2.GetValue();
	}

	template<typename...Ts>
	auto min(Ts&&... xs) {
		return std::min({ std::forward<Ts>(xs)... }, std::less<>());
	}

	template<typename...Ts>
	auto max(Ts&&... xs) {
		return std::max({ std::forward<Ts>(xs)... }, std::less<>());
	}

	using uint64 = unsigned long long;
	using Int = Number<uint64>;
	using Char = Number<char>;
	using Schar = Number<signed char>;
	using Uchar = Number<unsigned char>;
}

完整项目地址:c-plus-plus/number/number at master · 13870517674/c-plus-plus · GitHub

 它的检测仍有问题,如有建议还望告知

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值