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++17
auto 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++17
auto 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.hpp"
Definitions:
/// \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++17
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++17
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>
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?
std::sin
forCheckedNumber<T>
. \$\endgroup\$