There are a lot of times where you need to ensure that a number stays within some constraints and I got annoyed of inventing a distinct class for every case so I decided to solve the problem once and for all. So I wrote a template which has semantics the same as a number except it checks the predicate each time its value is about to change.Here are some design decisions:Compile time binding of predicate. I don't need runtime polymorphism.The violation of predicate should throw exception.The template will decay to underlying type as early as possible to allow intermediate values violate the predicate.It should be usable in any construct that accepts fundamental arithmetic types.On the other hand, it should work for arbitrary precision types as long as they have the same interface as fundamental types.It should be possible to derive from the template to add additional functions.Declarations:/// \file/// \brief Header file that describes the CheckedNumber class template./// \author Lyberta/// \copyright GNU GPLv3 or any later version.#pragma once#include <istream>#include <ostream>namespace ftz{namespace General{/// \brief A concept for a predicate.template <typename T>concept bool Predicate(){    return requires()    {        typename T::ValueType;    } &&    requires (typename T::ValueType value)    {        {T::Check(value)} -> void;    };}/// \brief A checked number./// \details Checked number is a number which can't have some values which are/// otherwise possible for the underlying type. For example, a floating point/// number which can't be negative. This class takes a predicate class which/// defines the underlying type of the value and a static function to check the/// value. Predicate must throw std::domain_error if the value is illegal./// \tparam T Type of the predicate.template <Predicate T>class CheckedNumber{public:    using ValueType = typename T::ValueType; ///< Underlying type of the value.    /// \brief Constructor.    /// \param[in] val Value to set.    /// \throw std::domain_error If value is illegal.    constexpr explicit CheckedNumber(ValueType val = ValueType{});    /// \brief Returns the reference to the underlying value.    /// \return Reference to the underlying value.    constexpr const ValueType& GetValue() const noexcept;    /// \brief Sets the underlying value.    /// \param[in] newvalue Value to set.    /// \return No return.    constexpr void SetValue(ValueType newvalue);    /// \brief Returns the underlying value.    /// \return Underlying value.    constexpr operator ValueType() const noexcept;    /// \brief Sets the underlying value.    /// \param[in] newvalue Value to set.    /// \return Reference to this number.    /// \throw std::domain_error If value is illegal.    constexpr CheckedNumber& operator=(ValueType newvalue);    /// \brief Converts the underlying value to boolean.    /// \return Result of the conversion.    constexpr explicit operator bool() const;    /// \brief Converts the underlying value to boolean and negates it.    /// \return Negated result of the conversion.    constexpr bool operator!() const;    /// \brief Returns the underlying value.    /// \return Underlying value.    constexpr auto operator+() const;    /// \brief Returns the underlying value with changed sign.    /// \return Underlying value with changed sign.    constexpr auto operator-() const;    /// \brief Returns the binary negated underlying value.    /// \return Binary negated underlying value.    constexpr auto operator~() const;    /// \brief Preincrements the underlying value.    /// \return Reference to this number.    /// \throw std::domain_error if result is illegal.    CheckedNumber& operator++();    /// \brief Postincrements the underlying value.    /// \return Copy of this number before increment.    /// \throw std::domain_error if result is illegal.    CheckedNumber operator++(int);    /// \brief Predecrements the underlying value.    /// \return Reference to this number.    /// \throw std::domain_error if result is illegal.    CheckedNumber& operator--();    /// \brief Postdecrements the underlying value.    /// \return Copy of this number before decrement.    /// \throw std::domain_error if result is illegal.    CheckedNumber operator--(int);    /// \brief Adds a value to the underlying value.    /// \tparam U Type of the value.    /// \param[in] val Value to add.    /// \return Reference to this number.    /// \throw std::domain_error If the sum is illegal.    template <typename U>    CheckedNumber& operator+=(const U& val);    /// \brief Subtracts a value from the underlying value.    /// \tparam U Type of the value.    /// \param[in] val Value to subtract.    /// \return Reference to this number.    /// \throw std::domain_error If the difference is illegal.    template <typename U>    CheckedNumber& operator-=(const U& val);    /// \brief Mulptiplies the underlying value by another value.    /// \tparam U Type of the value.    /// \param[in] val Value to multiply by.    /// \return Reference to this number.    /// \throw std::domain_error If the product is illegal.    template <typename U>    CheckedNumber& operator*=(const U& val);    /// \brief Divides the underlying value by another value.    /// \tparam U Type of the value.    /// \param[in] val Value to divide by.    /// \return Reference to this number.    /// \throw std::domain_error If the quotient is illegal.    template <typename U>    CheckedNumber& operator/=(const U& val);    /// \brief Computes the remainder of the division by another value.    /// \tparam U Type of the value.    /// \param[in] val Value to divide by.    /// \return Reference to this number.    /// \throw std::domain_error If the remainder is illegal.    template <typename U>    CheckedNumber& operator%=(const U& val);    /// \brief Computes bitwise AND of underlying value and another value.    /// \tparam U Type of the value.    /// \param[in] val Value to compute with.    /// \return Reference to this number.    /// \throw std::domain_error If the result is illegal.    template <typename U>    CheckedNumber& operator&=(const U& val);    /// \brief Computes bitwise OR of underlying value and another value.    /// \tparam U Type of the value.    /// \param[in] val Value to compute with.    /// \return Reference to this number.    /// \throw std::domain_error If the result is illegal.    template <typename U>    CheckedNumber& operator|=(const U& val);    /// \brief Computes bitwise XOR of underlying value and another value.    /// \tparam U Type of the value.    /// \param[in] val Value to compute with.    /// \return Reference to this number.    /// \throw std::domain_error If the result is illegal.    template <typename U>    CheckedNumber& operator^=(const U& val);    /// \brief Shifts the underlying value by several places to the left.    /// \tparam U Type of the value.    /// \param[in] val Value to shift by.    /// \return Reference to this number.    /// \throw std::domain_error If the result is illegal.    template <typename U>    CheckedNumber& operator<<=(const U& val);    /// \brief Shifts the underlying value by several places to the right.    /// \tparam U Type of the value.    /// \param[in] val Value to shift by.    /// \return Reference to this number.    /// \throw std::domain_error If the result is illegal.    template <typename U>    CheckedNumber& operator>>=(const U& val);private:    ValueType value; ///< Underlying value.};/// \brief Adds two numbers together./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Sum of the numbers.template <Predicate T, Predicate U>auto operator+(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Adds two numbers together./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Sum of the numbers.template <Predicate T, typename U>auto operator+(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Adds two numbers together./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Sum of the numbers.template <Predicate T, typename U>auto operator+(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Subtracts one number from the other./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs Number to subtract from./// \param[in] rhs Number to subtracts./// \return Difference between the numbers.template <Predicate T, Predicate U>auto operator-(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Subtracts one number from the other./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs Number to subtract from./// \param[in] rhs Number to subtracts./// \return Difference between the numbers.template <Predicate T, typename U>auto operator-(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Subtracts one number from the other./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs Number to subtract from./// \param[in] rhs Number to subtracts./// \return Difference between the numbers.template <Predicate T, typename U>auto operator-(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Multiplies two numbers together./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Product of the numbers.template <Predicate T, Predicate U>auto operator*(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Multiplies two numbers together./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Product of the numbers.template <Predicate T, typename U>auto operator*(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Multiplies two numbers together./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Product of the numbers.template <Predicate T, typename U>auto operator*(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Divides one number by the other./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs Number to divide./// \param[in] rhs Number to divide by./// \return Quotient of the numbers.template <Predicate T, Predicate U>auto operator/(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Divides one number by the other./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs Number to divide./// \param[in] rhs Number to divide by./// \return Quotient of the numbers.template <Predicate T, typename U>auto operator/(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Divides one number by the other./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs Number to divide./// \param[in] rhs Number to divide by./// \return Quotient of the numbers.template <Predicate T, typename U>auto operator/(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Returns the remainder of the division of two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs Number to divide./// \param[in] rhs Number to divide by./// \return Remainder of the division.template <Predicate T, Predicate U>auto operator%(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Returns the remainder of the division of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs Number to divide./// \param[in] rhs Number to divide by./// \return Remainder of the division.template <Predicate T, typename U>auto operator%(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Returns the remainder of the division of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs Number to divide./// \param[in] rhs Number to divide by./// \return Remainder of the division.template <Predicate T, typename U>auto operator%(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Returns the bitwise AND of two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Bitwise AND of two numbers.template <Predicate T, Predicate U>auto operator&(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Returns the bitwise AND of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Bitwise AND of two numbers.template <Predicate T, typename U>auto operator&(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Returns the bitwise AND of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Bitwise AND of two numbers.template <Predicate T, typename U>auto operator&(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Returns the bitwise OR of two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Bitwise OR of two numbers.template <Predicate T, Predicate U>auto operator|(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Returns the bitwise OR of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Bitwise OR of two numbers.template <Predicate T, typename U>auto operator|(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Returns the bitwise OR of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Bitwise OR of two numbers.template <Predicate T, typename U>auto operator|(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Returns the bitwise XOR of two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Bitwise OR of two numbers.template <Predicate T, Predicate U>auto operator^(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Returns the bitwise XOR of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Bitwise OR of two numbers.template <Predicate T, typename U>auto operator^(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Returns the bitwise XOR of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Bitwise OR of two numbers.template <Predicate T, typename U>auto operator^(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Returns the shift of the number by several places to the left./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs Number to shift./// \param[in] rhs Number to shift by./// \return Result of the shift.template <Predicate T, Predicate U>auto operator<<(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Returns the shift of the number by several places to the left./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs Number to shift./// \param[in] rhs Number to shift by./// \return Result of the shift.template <Predicate T, typename U>auto operator<<(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Returns the shift of the number by several places to the left./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs Number to shift./// \param[in] rhs Number to shift by./// \return Result of the shift.template <Predicate T, typename U,std::enable_if_t<!std::is_base_of<std::ios_base, U>::value>>//std::enable_if_t<!std::is_base_of_v<std::ios_base, U>>> C++17auto operator<<(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Returns the shift of the number by several places to the right./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs Number to shift./// \param[in] rhs Number to shift by./// \return Result of the shift.template <Predicate T, Predicate U>auto operator>>(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Returns the shift of the number by several places to the right./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs Number to shift./// \param[in] rhs Number to shift by./// \return Result of the shift.template <Predicate T, typename U>auto operator>>(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Returns the shift of the number by several places to the right./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs Number to shift./// \param[in] rhs Number to shift by./// \return Result of the shift.template <Predicate T, typename U,std::enable_if_t<!std::is_base_of<std::ios_base, U>::value>>//std::enable_if_t<!std::is_base_of_v<std::ios_base, U>>> C++17auto operator>>(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Returns the logical AND of two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Logical AND of two numbers.template <Predicate T, Predicate U>auto operator&&(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Returns the logical AND of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Logical AND of two numbers.template <Predicate T, typename U>auto operator&&(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Returns the logical AND of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Logical AND of two numbers.template <Predicate T, typename U>auto operator&&(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Returns the logical OR of two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Logical OR of two numbers.template <Predicate T, Predicate U>auto operator||(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Returns the logical OR of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Logical OR of two numbers.template <Predicate T, typename U>auto operator||(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Returns the logical OR of two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return Logical OR of two numbers.template <Predicate T, typename U>auto operator||(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if numbers are equal, false otherwise.template <Predicate T, Predicate U>bool operator==(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if numbers are equal, false otherwise.template <Predicate T, typename U>bool operator==(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if numbers are equal, false otherwise.template <Predicate T, typename U>bool operator==(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if numbers are not equal, false otherwise.template <Predicate T, Predicate U>bool operator!=(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if numbers are not equal, false otherwise.template <Predicate T, typename U>bool operator!=(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if numbers are not equal, false otherwise.template <Predicate T, typename U>bool operator!=(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is less than second, false otherwise.template <Predicate T, Predicate U>bool operator<(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is less than second, false otherwise.template <Predicate T, typename U>bool operator<(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is less than second, false otherwise.template <Predicate T, typename U>bool operator<(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is greater than second, false otherwise.template <Predicate T, Predicate U>bool operator>(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is greater than second, false otherwise.template <Predicate T, typename U>bool operator>(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is greater than second, false otherwise.template <Predicate T, typename U>bool operator>(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is less than or equal to second, false/// otherwise.template <Predicate T, Predicate U>bool operator<=(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is less than or equal to second, false/// otherwise.template <Predicate T, typename U>bool operator<=(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is less than or equal to second, false/// otherwise.template <Predicate T, typename U>bool operator<=(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is greater than or equal to second, false/// otherwise.template <Predicate T, Predicate U>bool operator>=(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is greater than or equal to second, false/// otherwise.template <Predicate T, typename U>bool operator>=(const CheckedNumber<T>& lhs, const U& rhs);/// \brief Compares two numbers./// \tparam T Predicate of the checked number./// \tparam U Type of another number./// \param[in] lhs First number./// \param[in] rhs Second number./// \return True if first number is greater than or equal to second, false/// otherwise.template <Predicate T, typename U>bool operator>=(const U& lhs, const CheckedNumber<T>& rhs);/// \brief Reads a number from stream./// \tparam T Predicate of the checked number./// \tparam CharT Character type of the stream./// \tparam Traits Traits type of the stream./// \param[in,out] stream Stream to read from./// \param[out] number Number to write to./// \return Reference to stream./// \throw std::domain_error If the value read is illegal.template <Predicate T, typename CharT, typename Traits>std::basic_istream<CharT, Traits>& operator>>(    std::basic_istream<CharT, Traits>& stream, CheckedNumber<T>& number);/// \brief Writes a number to stream./// \tparam T Predicate of the checked number./// \tparam CharT Character type of the stream./// \tparam Traits Traits type of the stream./// \param[in,out] stream Stream to write to./// \param[in] number Number to read from./// \return Reference to stream.template <Predicate T, typename CharT, typename Traits>std::basic_ostream<CharT, Traits>& operator<<(    std::basic_ostream<CharT, Traits>& stream, const CheckedNumber<T>& number);/// \brief Returns the absolute value of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Absolute value of the underlying value.template <Predicate T>auto abs(const CheckedNumber<T>& number);/// \brief Returns the e raised to the power of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return E raised to the power of the underlying value.template <Predicate T>auto exp(const CheckedNumber<T>& number);/// \brief Returns the natural logarithm of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Natural logarithm of the underlying value.template <Predicate T>auto log(const CheckedNumber<T>& number);/// \brief Returns the base-10 logarithm of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Base-10 logarithm of the underlying value.template <Predicate T>auto log10(const CheckedNumber<T>& number);/// \brief Returns the base raised to the power of the exponent./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] base Base value./// \param[in] exponent Exponent value./// \return Base raised to the power of the exponent.template <Predicate T, Predicate U>auto pow(const CheckedNumber<T>& base, const CheckedNumber<U>& exponent);/// \brief Returns the base raised to the power of the exponent./// \tparam T Predicate of the first checked number./// \tparam U Type of another number./// \param[in] base Base value./// \param[in] exponent Exponent value./// \return Base raised to the power of the exponent.template <Predicate T, typename U>auto pow(const CheckedNumber<T>& base, const U& exponent);/// \brief Returns the base raised to the power of the exponent./// \tparam T Predicate of the first checked number./// \tparam U Type of another number./// \param[in] base Base value./// \param[in] exponent Exponent value./// \return Base raised to the power of the exponent.template <Predicate T, typename U>auto pow(const U& base, const CheckedNumber<T>& exponent);/// \brief Returns the square root of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Square root of the underlying value.template <Predicate T>auto sqrt(const CheckedNumber<T>& number);/// \brief Returns the sine of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Sine of the underlying value.template <Predicate T>auto sin(const CheckedNumber<T>& number);/// \brief Returns the cosine of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Cosine of the underlying value.template <Predicate T>auto cos(const CheckedNumber<T>& number);/// \brief Returns the tangent of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Tangent of the underlying value.template <Predicate T>auto tan(const CheckedNumber<T>& number);/// \brief Returns the Arc sine of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Arc sine of the underlying value.template <Predicate T>auto asin(const CheckedNumber<T>& number);/// \brief Returns the arc cosine of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Arc cosine of the underlying value.template <Predicate T>auto acos(const CheckedNumber<T>& number);/// \brief Returns the arc tangent of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Arc tangent of the underlying value.template <Predicate T>auto atan(const CheckedNumber<T>& number);/// \brief Returns the arc tangent of y / x./// \tparam T Predicate of the first checked number./// \tparam U Predicate of the second checked number./// \param[in] y Y value./// \param[in] x X value./// \return Arc tangent of y / x.template <Predicate T, Predicate U>auto atan2(const CheckedNumber<T>& y, const CheckedNumber<U>& x);/// \brief Returns the arc tangent of y / x./// \tparam T Predicate of the first checked number./// \tparam U Type of another number./// \param[in] y Y value./// \param[in] x X value./// \return Arc tangent of y / x.template <Predicate T, typename U>auto atan2(const CheckedNumber<T>& y, const U& x);/// \brief Returns the arc tangent of y / x./// \tparam T Predicate of the first checked number./// \tparam U Type of another number./// \param[in] y Y value./// \param[in] x X value./// \return Arc tangent of y / x.template <Predicate T, typename U>auto atan2(const U& y, const CheckedNumber<T>& x);/// \brief Returns the hyperbolic sine of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Hyperbolic sine of the underlying value.template <Predicate T>auto sinh(const CheckedNumber<T>& number);/// \brief Returns the hyperbolic cosine of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Hyperbolic cosine of the underlying value.template <Predicate T>auto cosh(const CheckedNumber<T>& number);/// \brief Returns the hyperbolic tangent of the underlying value./// \tparam T Predicate of the checked number./// \param[in] number Input value./// \return Hyperbolic tangent of the underlying value.template <Predicate T>auto tanh(const CheckedNumber<T>& number);}}#include CheckedNumber.hppDefinitions:/// \file/// \brief Internal header file that contains implementation of the/// CheckedNumber class template./// \author Lyberta/// \copyright GNU GPLv3 or any later version.#pragma once#include <cmath>namespace ftz{namespace General{template <typename T>constexpr CheckedNumber<T>::CheckedNumber(ValueType val)    : value{std::move(val)}{    T::Check(value);}template <typename T>constexpr const typename CheckedNumber<T>::ValueType& CheckedNumber<T>::    GetValue() const noexcept{    return value;}template <typename T>constexpr void CheckedNumber<T>::SetValue(ValueType newvalue){    T::Check(newvalue);    value = std::move(newvalue);}template <typename T>constexpr CheckedNumber<T>::operator ValueType() const noexcept{    return value;}template <typename T>constexpr CheckedNumber<T>& CheckedNumber<T>::operator=(ValueType newvalue){    T::Check(newvalue);    value = std::move(newvalue);}template <typename T>constexpr CheckedNumber<T>::operator bool() const{    return value;}template <typename T>constexpr bool CheckedNumber<T>::operator!() const{    return !value;}template <typename T>constexpr auto CheckedNumber<T>::operator+() const{    return +value;}template <typename T>constexpr auto CheckedNumber<T>::operator-() const{    return -value;}template <typename T>constexpr auto CheckedNumber<T>::operator~() const{    return ~value;}template <typename T>CheckedNumber<T>& CheckedNumber<T>::operator++(){    ValueType result = value;    ++result;    T::Check(result);    value = std::move(result);    return *this;}template <typename T>CheckedNumber<T> CheckedNumber<T>::operator++(int){    CheckedNumber<T> savedvalue{value};    ValueType result = value;    result++;    T::Check(result);    value = std::move(result);    return savedvalue;}template <typename T>CheckedNumber<T>& CheckedNumber<T>::operator--(){    ValueType result = value;    --result;    T::Check(result);    value = std::move(result);    return *this;}template <typename T>CheckedNumber<T> CheckedNumber<T>::operator--(int){    CheckedNumber<T> savedvalue{value};    ValueType result = value;    result--;    T::Check(result);    value = std::move(result);    return savedvalue;}template <typename T> template <typename U>CheckedNumber<T>& CheckedNumber<T>::operator+=(const U& val){    ValueType result = value + val;    T::Check(result);    value = std::move(result);    return *this;}template <typename T> template <typename U>CheckedNumber<T>& CheckedNumber<T>::operator-=(const U& val){    ValueType result = value - val;    T::Check(result);    value = std::move(result);    return *this;}template <typename T> template <typename U>CheckedNumber<T>& CheckedNumber<T>::operator*=(const U& val){    ValueType result = value * val;    T::Check(result);    value = std::move(result);    return *this;}template <typename T> template <typename U>CheckedNumber<T>& CheckedNumber<T>::operator/=(const U& val){    ValueType result = value / val;    T::Check(result);    value = std::move(result);    return *this;}template <typename T> template <typename U>CheckedNumber<T>& CheckedNumber<T>::operator%=(const U& val){    ValueType result = value % val;    T::Check(result);    value = std::move(result);    return *this;}template <typename T> template <typename U>CheckedNumber<T>& CheckedNumber<T>::operator&=(const U& val){    ValueType result = value & val;    T::Check(result);    value = std::move(result);    return *this;}template <typename T> template <typename U>CheckedNumber<T>& CheckedNumber<T>::operator|=(const U& val){    ValueType result = value | val;    T::Check(result);    value = std::move(result);    return *this;}template <typename T> template <typename U>CheckedNumber<T>& CheckedNumber<T>::operator^=(const U& val){    ValueType result = value | val;    T::Check(result);    value = std::move(result);    return *this;}template <typename T> template <typename U>CheckedNumber<T>& CheckedNumber<T>::operator<<=(const U& val){    ValueType result = value << val;    T::Check(result);    value = std::move(result);    return *this;}template <typename T> template <typename U>CheckedNumber<T>& CheckedNumber<T>::operator>>=(const U& val){    ValueType result = value >> val;    T::Check(result);    value = std::move(result);    return *this;}template <Predicate T, Predicate U>auto operator+(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() + rhs.GetValue();}template <Predicate T, typename U>auto operator+(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() + rhs;}template <Predicate T, typename U>auto operator+(const U& lhs, const CheckedNumber<T>& rhs){    return lhs + rhs.GetValue();}template <Predicate T, Predicate U>auto operator-(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() - rhs.GetValue();}template <Predicate T, typename U>auto operator-(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() - rhs;}template <Predicate T, typename U>auto operator-(const U& lhs, const CheckedNumber<T>& rhs){    return lhs - rhs.GetValue();}template <Predicate T, Predicate U>auto operator*(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() * rhs.GetValue();}template <Predicate T, typename U>auto operator*(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() * rhs;}template <Predicate T, typename U>auto operator*(const U& lhs, const CheckedNumber<T>& rhs){    return lhs * rhs.GetValue();}template <Predicate T, Predicate U>auto operator/(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() + rhs.GetValue();}template <Predicate T, typename U>auto operator/(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() / rhs;}template <Predicate T, typename U>auto operator/(const U& lhs, const CheckedNumber<T>& rhs){    return lhs / rhs.GetValue();}template <Predicate T, Predicate U>auto operator%(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() + rhs.GetValue();}template <Predicate T, typename U>auto operator%(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() + rhs;}template <Predicate T, typename U>auto operator%(const U& lhs, const CheckedNumber<T>& rhs){    return lhs + rhs.GetValue();}template <Predicate T, Predicate U>auto operator&(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() & rhs.GetValue();}template <Predicate T, typename U>auto operator&(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() & rhs;}template <Predicate T, typename U>auto operator&(const U& lhs, const CheckedNumber<T>& rhs){    return lhs & rhs.GetValue();}template <Predicate T, Predicate U>auto operator|(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() | rhs.GetValue();}template <Predicate T, typename U>auto operator|(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() | rhs;}template <Predicate T, typename U>auto operator|(const U& lhs,    const CheckedNumber<T>& rhs){    return lhs | rhs.GetValue();}template <Predicate T, Predicate U>auto operator^(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() ^ rhs.GetValue();}template <Predicate T, typename U>auto operator^(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() ^ rhs;}template <Predicate T, typename U>auto operator^(const U& lhs, const CheckedNumber<T>& rhs){    return lhs ^ rhs.GetValue();}template <Predicate T, Predicate U>auto operator<<(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() << rhs.GetValue();}template <Predicate T, typename U>auto operator<<(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() << rhs;}template <Predicate T, typename U,std::enable_if_t<!std::is_base_of<std::ios_base, U>::value>>//std::enable_if_t<!std::is_base_of_v<std::ios_base, U>>> C++17auto operator<<(const U& lhs, const CheckedNumber<T>& rhs){    return lhs << rhs.GetValue();}template <Predicate T, Predicate U>auto operator>>(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() >> rhs.GetValue();}template <Predicate T, typename U>auto operator>>(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() >> rhs;}template <Predicate T, typename U,std::enable_if_t<!std::is_base_of<std::ios_base, U>::value>>//std::enable_if_t<!std::is_base_of_v<std::ios_base, U>>> C++17auto operator>>(const U& lhs, const CheckedNumber<T>& rhs){    return lhs >> rhs.GetValue();}template <Predicate T, Predicate U>auto operator&&(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() && rhs.GetValue();}template <Predicate T, typename U>auto operator&&(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() && rhs;}template <Predicate T, typename U>auto operator&&(const U& lhs, const CheckedNumber<T>& rhs){    return lhs && rhs.GetValue();}template <Predicate T, Predicate U>auto operator||(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() || rhs.GetValue();}template <Predicate T, typename U>auto operator||(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() || rhs;}template <Predicate T, typename U>auto operator||(const U& lhs, const CheckedNumber<T>& rhs){    return lhs || rhs.GetValue();}template <Predicate T, Predicate U>bool operator==(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() == rhs.GetValue();}template <Predicate T, typename U>bool operator==(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() == rhs;}template <Predicate T, typename U>bool operator==(const U& lhs, const CheckedNumber<T>& rhs){    return lhs == rhs.GetValue();}template <Predicate T, Predicate U>bool operator!=(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() != rhs.GetValue();}template <Predicate T, typename U>bool operator!=(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() != rhs;}template <Predicate T, typename U>bool operator!=(const U& lhs, const CheckedNumber<T>& rhs){    return lhs != rhs.GetValue();}template <Predicate T, Predicate U>bool operator<(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() < rhs.GetValue();}template <Predicate T, typename U>bool operator<(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() < rhs;}template <Predicate T, typename U>bool operator<(const U& lhs, const CheckedNumber<T>& rhs){    return lhs < rhs.GetValue();}template <Predicate T, Predicate U>bool operator>(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() > rhs.GetValue();}template <Predicate T, typename U>bool operator>(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() > rhs;}template <Predicate T, typename U>bool operator>(const U& lhs, const CheckedNumber<T>& rhs){    return lhs > rhs.GetValue();}template <Predicate T, Predicate U>bool operator<=(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() <= rhs.GetValue();}template <Predicate T, typename U>bool operator<=(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() <= rhs;}template <Predicate T, typename U>bool operator<=(const U& lhs, const CheckedNumber<T>& rhs){    return lhs <= rhs.GetValue();}template <Predicate T, Predicate U>bool operator>=(const CheckedNumber<T>& lhs, const CheckedNumber<U>& rhs){    return lhs.GetValue() >= rhs.GetValue();}template <Predicate T, typename U>bool operator>=(const CheckedNumber<T>& lhs, const U& rhs){    return lhs.GetValue() >= rhs;}template <Predicate T, typename U>bool operator>=(const U& lhs, const CheckedNumber<T>& rhs){    return lhs >= rhs.GetValue();}template <Predicate T, typename CharT, typename Traits>std::basic_istream<CharT, Traits>& operator>>(    std::basic_istream<CharT, Traits>& stream, CheckedNumber<T>& number){    typename CheckedNumber<T>::ValueType value;    stream >> value;    number = value;    return stream;}template <Predicate T, typename CharT, typename Traits>std::basic_ostream<CharT, Traits>& operator<<(    std::basic_ostream<CharT, Traits>& stream, const CheckedNumber<T>& number){    stream << number.GetValue();    return stream;}template <Predicate T>auto abs(const CheckedNumber<T>& number){    using std::abs;    return abs(number.GetValue());}template <Predicate T, typename U>auto exp(const CheckedNumber<T>& number, const U& exponent){    using std::exp;    return exp(number.GetValue(),        exponent);}template <Predicate T>auto log(const CheckedNumber<T>& number){    using std::log;    return log(number.GetValue());}template <Predicate T>auto log10(const CheckedNumber<T>& number){    using std::log10;    return log10(number.GetValue());}template <Predicate T, Predicate U>auto pow(const CheckedNumber<T>& base, const CheckedNumber<U>& exponent){    using std::pow;    return pow(base.GetValue(), exponent.GetValue());}template <Predicate T, typename U>auto pow(const CheckedNumber<T>& base, const U& exponent){    using std::pow;    return pow(base.GetValue(), exponent);}template <Predicate T, typename U>auto pow(const U& base, const CheckedNumber<T>& exponent){    using std::pow;    return pow(base, exponent.GetValue());}template <Predicate T>auto sqrt(const CheckedNumber<T>& number){    using std::sqrt;    return sqrt(number.GetValue());}template <Predicate T>auto sin(const CheckedNumber<T>& number){    using std::sin;    return sin(number.GetValue());}template <Predicate T>auto cos(const CheckedNumber<T>& number){    using std::cos;    return cos(number.GetValue());}template <Predicate T>auto tan(const CheckedNumber<T>& number){    using std::tan;    return tan(number.GetValue());}template <Predicate T>auto asin(const CheckedNumber<T>& number){    using std::asin;    return asin(number.GetValue());}template <Predicate T>auto acos(const CheckedNumber<T>& number){    using std::acos;    return acos(number.GetValue());}template <Predicate T>auto atan(const CheckedNumber<T>& number){    using std::atan;    return atan(number.GetValue());}template <Predicate T, Predicate U>auto atan2(const CheckedNumber<T>& y, const CheckedNumber<U>& x){    using std::atan2;    return atan2(y.GetValue(), x.GetValue());}template <Predicate T, typename U>auto atan2(const CheckedNumber<T>& y, const U& x){    using std::atan2;    return atan2(y.GetValue(), x);}template <Predicate T, typename U>auto atan2(const U& y, const CheckedNumber<T>& x){    using std::atan2;    return atan2(y, x.GetValue());}template <Predicate T>auto sinh(const CheckedNumber<T>& number){    using std::sinh;    return abs(number.GetValue());}template <Predicate T>auto cosh(const CheckedNumber<T>& number){    using std::cosh;    return cosh(number.GetValue());}template <Predicate T>auto atanh(const CheckedNumber<T>& number){    using std::atanh;    return atanh(number.GetValue());}}}Now first, I've started marking functions constexpr but quickly found that I don't have much knowledge of constexpr so I don't know which functions should be constexpr. Which ones? It looks like I can mark all functions constexpr.Second, I haven't added non-operator functions such as abs or sin. I'd want to overload std versions (this is how std::complex and std::valarray do this) but it looks like it is undefined behavior. So I don't know what to do. Suggestions?EDIT: OK, since I can't overload std functions, I've put them in the same namespace as template so I'd need to use unqualified, say, abs, and rely on ADL. So far, I've added all functions that are declared for std::valarray but it looks like C++11 and 14 added more stuff to <cmath> so I'll add them too.EDIT2: I've just found that if I derive from this template, I need to import all overloaded operators into the derived class. Is there a better way?
Constrained number template
c++;c++14