Created
December 12, 2014 14:04
-
-
Save gnzlbg/7714403baeef9bcd4be9 to your computer and use it in GitHub Desktop.
arithmetic type
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
#pragma once | |
/// \file arithmetic.hpp Arithmetic type without implicit conversions | |
#include <type_traits> | |
#include <limits> | |
#include <algorithm> | |
/// Arithmetic type without implicit conversions | |
template <class T, class B = void> struct arithmetic { | |
using value_type = T; | |
// using difference_type = arithmetic<T, B>; | |
using type = T; | |
/// \name Asignment operators | |
///@{ | |
constexpr arithmetic() = default; | |
constexpr arithmetic(const arithmetic& other) = default; | |
constexpr arithmetic(arithmetic&& other) = default; | |
constexpr arithmetic& operator=(const arithmetic& other) = default; | |
constexpr arithmetic& operator=(arithmetic&& other) = default; | |
constexpr explicit arithmetic(const T& other) noexcept( | |
std::is_nothrow_constructible<T>::value) | |
: value{other} {} | |
template <class U, class V> | |
constexpr explicit arithmetic(const arithmetic<U, V>& other) noexcept( | |
std::is_nothrow_constructible<T>::value) | |
: value(other.value) {} | |
constexpr arithmetic& operator=(constant::invalid) noexcept { | |
value = invalid; | |
return *this; | |
} | |
///@} | |
/// \name Conversion operators | |
///@{ | |
explicit constexpr operator T() noexcept { return value; } | |
explicit constexpr operator const T() const noexcept { return value; } | |
template <class U, class V> | |
explicit constexpr operator arithmetic<U, V>() noexcept { | |
return value; | |
} | |
template <class U, class V> | |
explicit constexpr operator const arithmetic<U, V>() const noexcept { | |
return value; | |
} | |
///@} | |
/// \name Compound assignment +=, -=, *=, /= | |
///@{ | |
constexpr arithmetic& operator+=(const arithmetic& other) noexcept { | |
value += other.value; | |
return *this; | |
} | |
constexpr arithmetic& operator-=(const arithmetic& other) noexcept { | |
value -= other.value; | |
return *this; | |
} | |
constexpr arithmetic& operator+=(const T& other) noexcept { | |
value += other; | |
return *this; | |
} | |
constexpr arithmetic& operator-=(const T& other) noexcept { | |
value -= other; | |
return *this; | |
} | |
constexpr arithmetic& operator*=(const arithmetic& other) noexcept { | |
value *= other.value; | |
return *this; | |
} | |
constexpr arithmetic& operator/=(const arithmetic& other) noexcept { | |
value /= other.value; | |
return *this; | |
} | |
///@} | |
/// \name Prefix increment operators ++(),--() | |
///@{ | |
constexpr arithmetic& operator++() noexcept { | |
++value; | |
return *this; | |
} | |
constexpr arithmetic& operator--() noexcept { | |
--value; | |
return *this; | |
} | |
///@} | |
/// \name Postfix increment operators ()++,()-- | |
///@{ | |
constexpr arithmetic operator++(int) noexcept { | |
arithmetic tmp(*this); | |
++(*this); | |
return tmp; | |
} | |
constexpr arithmetic operator--(int) noexcept { | |
arithmetic tmp(*this); | |
--(*this); | |
return tmp; | |
} | |
///@} | |
/// \name Access operator | |
///@{ | |
constexpr T& operator()() & noexcept { return value; } | |
constexpr T operator()() && noexcept { return value; } | |
constexpr T operator()() const& noexcept { return value; } | |
///@} | |
/// Data (wrapped value): | |
T value; | |
/// \name Comparison operators ==, !=, <, >, <=, >= | |
/// \relates arithmetic<T, U> | |
///@{ | |
constexpr bool operator==(const constant::invalid) { | |
return value == T{invalid}; | |
} | |
}; | |
///@} | |
/// swap | |
/// \relates arithmetic<T, U> | |
template <class T, class U> | |
constexpr void swap(arithmetic<T, U>&& a, arithmetic<T, U>&& b) noexcept { | |
using std::swap; | |
swap(a.value, b.value); | |
} | |
/// \name arithmetic operators +,-,*,/,unary - | |
/// \relates arithmetic<T, U> | |
///@{ | |
template <class T, class U> | |
constexpr arithmetic<T, U> operator+(arithmetic<T, U> a, | |
const arithmetic<T, U>& b) noexcept { | |
return a += b; | |
} | |
template <class T, class U> | |
constexpr arithmetic<T, U> operator-(arithmetic<T, U> a, | |
const arithmetic<T, U>& b) noexcept { | |
return a -= b; | |
} | |
template <class T, class U> | |
constexpr arithmetic<T, U> operator*(arithmetic<T, U> a, | |
const arithmetic<T, U>& b) noexcept { | |
return a *= b; | |
} | |
template <class T, class U> | |
constexpr arithmetic<T, U> operator/(arithmetic<T, U> a, | |
const arithmetic<T, U>& b) noexcept { | |
return a /= b; | |
} | |
template <class T, class U> | |
constexpr arithmetic<T, U> operator-(arithmetic<T, U> const& other) noexcept { | |
return arithmetic<T, U>{-other.value}; | |
} | |
///@} | |
/// \name Comparison operators ==, !=, <, >, <=, >= | |
/// \relates arithmetic<T, U> | |
///@{ | |
template <class T, class U> | |
constexpr bool operator==(const arithmetic<T, U>& a, | |
const arithmetic<T, U>& b) noexcept { | |
return a.value == b.value; | |
} | |
template <class T, class U> | |
constexpr bool operator<(const arithmetic<T, U>& a, | |
const arithmetic<T, U>& b) noexcept { | |
return a.value < b.value; | |
} | |
template <class T, class U> | |
constexpr bool operator<=(const arithmetic<T, U>& a, | |
const arithmetic<T, U>& b) noexcept { | |
return a < b || a == b; | |
} | |
template <class T, class U> | |
constexpr bool operator!=(const arithmetic<T, U>& a, | |
const arithmetic<T, U>& b) noexcept { | |
return !(a == b); | |
} | |
template <class T, class U> | |
constexpr bool operator>(const arithmetic<T, U>& a, | |
const arithmetic<T, U>& b) noexcept { | |
return !(a <= b); | |
} | |
template <class T, class U> | |
constexpr bool operator>=(const arithmetic<T, U>& a, | |
const arithmetic<T, U>& b) noexcept { | |
return !(a < b); | |
}ho | |
/// istream operator | |
template <class C, class CT, class T, class B> | |
inline auto operator>>(std::basic_istream<C, CT>& i, arithmetic<T, B>& v) | |
-> decltype(i >> v()) { | |
return i >> v(); | |
} | |
/// ostream operator | |
template <class C, class CT, class T, class B> | |
inline auto operator<<(std::basic_ostream<C, CT>& o, const arithmetic<T, B>& v) | |
-> decltype(o << v()) { | |
return o << v(); | |
} | |
/// to_string | |
template <class T, class U> | |
inline std::string to_string(const arithmetic<T, U> a) { | |
return std::to_string(a()); | |
} | |
/// \name arithmetic types are numeric / integral types | |
/// \relates arithmetic<T, U> | |
///@{ | |
namespace std { | |
template <class T, class B> | |
class numeric_limits<arithmetic<T, B>> : public numeric_limits<T> { | |
public: | |
static constexpr bool is_specialized = true; | |
}; | |
template <class T, class U> | |
struct is_integral<arithmetic<T, U>> : std::true_type {}; | |
} // namespace std | |
///@} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment