I've prepared a safe integer type that now works with random number generators on the bit level but is it really safe? I've engaged some ideas from this community (SiCrane and the_Edd) as well as Meyers'
Effective C++ 3rd Ed, Solter's and Kleper's
Professional C++ and Stroustrup's
The C++ Programming Language. But now it's put to the real experts...:-}
Anyway, the idea is to:
1. Only allow integral type promotion.
2. Stop signed/unsigned assignment and copying.
3. Check for division by zero.
4. Make assertions on all allowable type conversion conditions.
5. Make a lightweight class of the same bit (byte) size as the underlying primitive type.
//
// IntT.hpp
//
// September 27 2007 : Compiles OK.
//
// Defines integral types in namespace 'STBase'.
//
#ifndef __INTT_HPP
#define __INTT_HPP
#include <iostream>
#include "Limits.hpp"
#include "Assertions.hpp"
#include "Operators.hpp"
#include "Streams.hpp"
#include "../Utilities/Error.hpp"
namespace STBase
{
template <typename intT>
class int_t
{
public:
// Basic intitialization, no checks needed, it's the base type.
int_t() :
value_(0)
{
}
// Intitialize with same type, no checks needed, it's the same type.
int_t(const int_t &type) :
value_(type.value())
{
}
// Inititalize with other int_t type, assert type.
template <typename otherT>
explicit int_t(int_t<otherT> type) :
value_(assert_type<otherT,intT>(type.value()))
{
}
// Initialize with other primitive types, assert type.
template <typename otherT>
explicit int_t<intT>(otherT value) :
value_(assert_type<otherT,intT>(value))
{
}
// Assign with same type, no checks needed, it's the same type.
int_t &operator=(const int_t &type)
{
value_ = type.value();
return *this;
}
// Assign other int_t type, assert type.
template <typename otherT>
int_t &operator=(int_t<otherT> type)
{
value_ = assert_type<otherT,intT>(type.value());
return *this;
}
// Assign other primitive types, assert type.
template <typename otherT>
int_t &operator=(otherT value)
{
value_ = assert_type<otherT,intT>(value);
return *this;
}
// Type conversion operator, assert type.
template <typename otherT>
operator otherT() const
{
return assert_type<otherT,intT>(value());
}
// Complement, no checks needed.
const int_t &operator~() const
{
int_t copy(~value());
return copy;
}
// Increment, no checks needed.
int_t &operator++()
{
++value_;
return *this;
}
// Post increment, no checks needed.
const int_t operator++(int)
{
int_t copy(*this);
++value_;
return copy;
}
// Decrement, no checks needed.
int_t &operator--()
{
--value_;
return *this;
}
// Post decrement, no checks needed.
const int_t operator--(int)
{
int_t copy(*this);
--value_;
return copy;
}
// Sum accumulator using primitive type, assert_type.
template <typename otherT>
int_t &operator+=(const otherT &unsafe_int)
{
value_ += assert_type<otherT,intT>(unsafe_int);
return *this;
}
// Sum accumulator using safe_int<primitive type>, assert_type.
template <typename otherT>
int_t &operator+=(const int_t<otherT> &unsafe_int)
{
value_ += assert_type<otherT,intT>(unsafe_int.value());
return *this;
}
// Difference accumulator using primitive type, assert_type.
template <typename otherT>
int_t &operator-=(const otherT &unsafe_int)
{
value_ -= assert_type<otherT,intT>(unsafe_int);
return *this;
}
// Difference accumulator using safe_int<primitive type>, assert_type.
template <typename otherT>
int_t &operator-=(const int_t<otherT> &unsafe_int)
{
value_ -= assert_type<otherT,intT>(unsafe_int.value());
return *this;
}
// Product accumulator using primitive type, assert_type.
template <typename otherT>
int_t &operator*=(const otherT &unsafe_int)
{
value_ *= assert_type<otherT,intT>(unsafe_int);
return *this;
}
// Product accumulator using safe_int<primitive type>, assert_type.
template <typename otherT>
int_t &operator*=(const int_t<otherT> &unsafe_int)
{
value_ *= assert_type<otherT,intT>(unsafe_int.value());
return *this;
}
// Quotient accumulator using primitive type, assert_type.
template <typename otherT>
int_t &operator/=(const otherT &unsafe_int)
{
if (unsafe_int == 0)
{
STUtility::error error_cond("Divide by zero");
error_cond.die();
}
value_ /= assert_type<otherT,intT>(unsafe_int);
return *this;
}
// Quotient accumulator using safe_int<primitive type>, assert_type.
template <typename otherT>
int_t &operator/=(const int_t<otherT> &unsafe_int)
{
if (unsafe_int.value() == 0)
{
STUtility::error error_cond("Divide by zero");
error_cond.die();
}
value_ /= assert_type<otherT,intT>(unsafe_int.value());
return *this;
}
// Right shift accumulator using primitive type, assert_type.
template <typename otherT>
int_t &operator>>=(const otherT &unsafe_int)
{
value_ >>= assert_type<otherT,intT>(unsafe_int);
return *this;
}
// Right shift accumulator using safe_int<primitive type>, assert_type.
template <typename otherT>
int_t &operator>>=(const int_t<otherT> &unsafe_int)
{
value_ >>= assert_type<otherT,intT>(unsafe_int.value());
return *this;
}
// Left shift accumulator using primitive type, assert_type.
template <typename otherT>
int_t &operator<<=(const otherT &unsafe_int)
{
value_ <<= assert_type<otherT,intT>(unsafe_int);
return *this;
}
// Left shift accumulator using safe_int<primitive type>, assert_type.
template <typename otherT>
int_t &operator<<=(const int_t<otherT> &unsafe_int)
{
value_ <<= assert_type<otherT,intT>(unsafe_int.value());
return *this;
}
// AND accumulator using primitive type, assert_type.
template <typename otherT>
int_t &operator&=(const otherT &unsafe_int)
{
value_ &= assert_type<otherT,intT>(unsafe_int);
return *this;
}
// AND accumulator using safe_int<primitive type>, assert_type.
template <typename otherT>
int_t &operator&=(const int_t<otherT> &unsafe_int)
{
value_ &= assert_type<otherT,intT>(unsafe_int.value());
return *this;
}
// OR accumulator using primitive type, assert_type.
template <typename otherT>
int_t &operator|=(const otherT &unsafe_int)
{
value_ |= assert_type<otherT,intT>(unsafe_int);
return *this;
}
// OR accumulator using safe_int<primitive type>, assert_type.
template <typename otherT>
int_t &operator|=(const int_t<otherT> &unsafe_int)
{
value_ |= assert_type<otherT,intT>(unsafe_int.value());
return *this;
}
// XOR accumulator using primitive type, assert_type.
template <typename otherT>
int_t &operator^=(const otherT &unsafe_int)
{
value_ ^= assert_type<otherT,intT>(unsafe_int);
return *this;
}
// XOR accumulator using safe_int<primitive type>, assert_type.
template <typename otherT>
int_t &operator^=(const int_t<otherT> &unsafe_int)
{
value_ ^= assert_type<otherT,intT>(unsafe_int.value());
return *this;
}
// Modulus accumulator using primitive type, assert_type.
template <typename otherT>
int_t &operator%=(const otherT &unsafe_int)
{
value_ %= assert_type<otherT,intT>(unsafe_int);
return *this;
}
// Modulus accumulator using safe_int<primitive type>, assert_type.
template <typename otherT>
int_t & operator%=(const int_t<otherT> &unsafe_int)
{
value_ %= assert_type<otherT,intT>(unsafe_int.value());
return *this;
}
// Return const reference to value, no checks needed, it's the same type.
const intT &operator*() const
{
return value();
}
// Return const pointer to value, no checks needed, it's the same type.
const intT *operator->() const
{
return &value();
}
// Return value, no checks needed, it's the same type.
const intT value() const
{
return value_;
}
// Minimum value of int_t.
static const intT min()
{
return integral_limits<intT>::min();
}
// Maximum value of int_t.
static const intT max()
{
return integral_limits<intT>::max();
}
// Have friends call helpers for binary operations...allows type conversions
// on all arguments plus mixed mode operations. Avoids operator ambiguity.
// Strongly advised by Meyers.
// Out stream for int_t.
friend std::ostream &operator<<(std::ostream &stream, const int_t &obj)
{
return out(stream,obj);
}
// In stream for int_t.
friend std::istream &operator>>(std::istream &stream, const int_t &obj)
{
return in(stream,obj);
}
// Sums. For int_t and primitive.
template <typename otherT>
friend const int_t operator+(const int_t &lhs,const otherT &rhs)
{
return sum(lhs,rhs);
}
// Sums. For int_t and other int_t.
template <typename otherT>
friend const int_t operator+(const int_t &lhs,const int_t<otherT> &rhs)
{
return sum(lhs,rhs);
}
// Differences. For int_t and primitive.
template <typename otherT>
friend const int_t operator-(const int_t &lhs,const otherT &rhs)
{
return difference(lhs,rhs);
}
// Differences. For int_t and other int_t.
template <typename otherT>
friend const int_t operator-(const int_t &lhs,const int_t<otherT> &rhs)
{
return difference(lhs,rhs);
}
// Products. For int_t and primitive.
template <typename otherT>
friend const int_t operator*(const int_t &lhs,const otherT &rhs)
{
return product(lhs,rhs);
}
// Products. For int_t and other int_t.
template <typename otherT>
friend const int_t operator*(const int_t &lhs,const int_t<otherT> &rhs)
{
return product(lhs,rhs);
}
// Quotients. For int_t and primitive.
template <typename otherT>
friend const int_t operator/(const int_t &lhs,const otherT &rhs)
{
return quotient(lhs,rhs);
}
// Quotients. For int_t and other int_t.
template <typename otherT>
friend const int_t operator/(const int_t &lhs,const int_t<otherT> &rhs)
{
return quotient(lhs,rhs);
}
// Modulus. For int_t and primitive.
template <typename otherT>
friend const int_t operator%(const int_t &lhs,const otherT &rhs)
{
return modulus(lhs,rhs);
}
// Modulus. For int_t and other int_t.
template <typename otherT>
friend const int_t operator%(const int_t &lhs,const int_t<otherT> &rhs)
{
return modulus(lhs,rhs);
}
// Bitwise AND. For int_t and primitive.
template <typename otherT>
friend const int_t operator&(const int_t &lhs,const otherT &rhs)
{
return bit_and(lhs,rhs);
}
// Bitwise AND. For int_t and other int_t.
template <typename otherT>
friend const int_t operator&(const int_t &lhs,const int_t<otherT> &rhs)
{
return bit_and(lhs,rhs);
}
// Bitwise OR. For int_t and primitive.
template <typename otherT>
friend const int_t operator|(const int_t &lhs,const otherT &rhs)
{
return bit_or(lhs,rhs);
}
// Bitwise OR. For int_t and other int_t.
template <typename otherT>
friend const int_t operator|(const int_t &lhs,const int_t<otherT> &rhs)
{
return bit_or(lhs,rhs);
}
// Bitwise XOR. For int_t and primitive.
template <typename otherT>
friend const int_t operator^(const int_t &lhs,const otherT &rhs)
{
return bit_xor(lhs,rhs);
}
// Bitwise XOR. For int_t and other int_t.
template <typename otherT>
friend const int_t operator^(const int_t &lhs,const int_t<otherT> &rhs)
{
return bit_xor(lhs,rhs);
}
// Bitwise RIGHT SHIFT. For int_t and primitive.
template <typename otherT>
friend const int_t operator>>(const int_t &lhs,const otherT &rhs)
{
return bit_shift_right(lhs,rhs);
}
// Bitwise RIGHT SHIFT. For int_t and other int_t.
template <typename otherT>
friend const int_t operator>>(const int_t &lhs,const int_t<otherT> &rhs)
{
return bit_shift_right(lhs,rhs);
}
// Bitwise LEFT SHIFT. For int_t and primitive.
template <typename otherT>
friend const int_t operator<<(const int_t &lhs,const otherT &rhs)
{
return bit_shift_left(lhs,rhs);
}
// Bitwise LEFT SHIFT. For int_t and other int_t.
template <typename otherT>
friend const int_t operator<<(const int_t &lhs,const int_t<otherT> &rhs)
{
return bit_shift_left(lhs,rhs);
}
template <typename otherT>
friend const bool operator==(const int_t &lhs,const otherT &rhs)
{
return isIntEqual(lhs,rhs);
}
template <typename otherT>
friend const bool operator==(const int_t &lhs,const int_t<otherT> &rhs)
{
return isIntEqual(lhs,rhs);
}
template <typename otherT>
friend const bool operator!=(const int_t &lhs,const otherT &rhs)
{
return isIntNotEqual(lhs,rhs);
}
template <typename otherT>
friend const bool operator!=(const int_t &lhs,const int_t<otherT> &rhs)
{
return isIntNotEqual(lhs,rhs);
}
template <typename otherT>
friend const bool operator>(const int_t &lhs,const otherT &rhs)
{
return isIntGreater(lhs,rhs);
}
template <typename otherT>
friend const bool operator>(const int_t &lhs,const int_t<otherT> &rhs)
{
return isIntGreater(lhs,rhs);
}
template <typename otherT>
friend const bool operator>=(const int_t &lhs,const otherT &rhs)
{
return isIntGreaterOrEqual(lhs,rhs);
}
template <typename otherT>
friend const bool operator>=(const int_t &lhs,const int_t<otherT> &rhs)
{
return isIntGreaterOrEqual(lhs,rhs);
}
template <typename otherT>
friend const bool operator<(const int_t &lhs,const otherT &rhs)
{
return isIntLess(lhs,rhs);
}
template <typename otherT>
friend const bool operator<(const int_t &lhs,const int_t<otherT> &rhs)
{
return isIntLess(lhs,rhs);
}
template <typename otherT>
friend const bool operator<=(const int_t &lhs,const otherT &rhs)
{
return isIntLessOrEqual(lhs,rhs);
}
template <typename otherT>
friend const bool operator<=(const int_t &lhs,const int_t<otherT> &rhs)
{
return isIntLessOrEqual(lhs,rhs);
}
private:
intT value_;
};
}
#endif
Can provide associated files Operators.hpp and Assertions.hpp if needed, but these are big.
--random
OK here's Assertions.hpp:
//
// Assertions.hpp
//
// September 27 2007 : Compiles OK.
//
// Defines assertions and allowable type conversions in namespace 'STBase'.
//
#ifndef __ASSERTIONS_HPP
#define __ASSERTIONS_HPP
#include "../Utilities/Error.hpp"
namespace STBase
{
// Base conversion templates.
template<typename fromT, typename toT>
struct allow_conversion
{
static const bool value = false;
};
template<typename fromT>
struct allow_conversion<fromT, fromT>
{
static const bool value = true;
};
// Specializations for real number conversions.
template<>
struct allow_conversion<double, long double>
{
static const bool value = true;
};
template<>
struct allow_conversion<float, long double>
{
static const bool value = true;
};
template<>
struct allow_conversion<float, double>
{
static const bool value = true;
};
// Specializations for signed integral conversions.
template<>
struct allow_conversion<long,long long>
{
static const bool value = true;
};
template<>
struct allow_conversion<int,long long>
{
static const bool value = true;
};
template<>
struct allow_conversion<char,long long>
{
static const bool value = true;
};
template<>
struct allow_conversion<int,long>
{
static const bool value = true;
};
template<>
struct allow_conversion<char,long>
{
static const bool value = true;
};
template<>
struct allow_conversion<char,int>
{
static const bool value = true;
};
// Specializations for unsigned integral conversions.
template<>
struct allow_conversion<unsigned long,unsigned long long>
{
static const bool value = true;
};
template<>
struct allow_conversion<unsigned int,unsigned long long>
{
static const bool value = true;
};
template<>
struct allow_conversion<unsigned char,unsigned long long>
{
static const bool value = true;
};
template<>
struct allow_conversion<unsigned int,unsigned long>
{
static const bool value = true;
};
template<>
struct allow_conversion<unsigned char,unsigned long>
{
static const bool value = true;
};
template<>
struct allow_conversion<unsigned char,unsigned int>
{
static const bool value = true;
};
// For use with 'assert_xxx()' 'assertion' template parameter.
enum { unsafe,safe };
// assert_type() returns permitted types, with a strictness option. 'safe' behaviour
// kills execution. Alternatively, 'unsafe' may be specified which will allow execution
// to continue with a warning to std::cerr.
template<typename T1,typename T2,int assertion_behaviour>
T2 assert_type(const T2 &value)
{
if (!allow_conversion<T1,T2>::value)
{
STUtility::error error_behaviour("Type conversion unsafe");
switch (assertion_behaviour)
{
case unsafe:
// Option 1. If not safe, allow survival.
// survive() continues execution with warning message.
error_behaviour.survive();
break;
case safe:
// Option 2. If safe, kill execution (default behaviour).
// die() kills execution with death message.
error_behaviour.die();
break;
default:
// If all else fails, default to safe behaviour (Option 2).
error_behaviour.die();
}
}
return value;
}
// Allow safe type assertion only.
template<typename T1,typename T2>
T2 assert_type(const T2 &arg)
{
return assert_type<T1,T2,safe>(arg);
}
// assert_limit() is used wherever assertions to limits is required. 'safe' behaviour
// kills execution. Alternatively, 'unsafe' may be specified which will allow execution
// to continue with a warning to std::cerr.
template<typename T1,typename T2,int assertion_behaviour>
T2 assert_limit(const T1 &limit,const T2 &value)
{
STUtility::error error_behaviour("Limits exceeded");
switch (assertion_behaviour)
{
case unsafe:
// Option 1. If not safe, allow survival.
// survive() continues execution with warning message.
error_behaviour.survive();
break;
case safe:
// Option 2. If safe, kill execution (default behaviour).
// die() kills execution with death message.
error_behaviour.die();
break;
default:
// If all else fails, default to safe behaviour (Option 2).
error_behaviour.die();
}
return value;
}
// Allow safe limit assertion only.
template<typename T1,typename T2>
T2 assert_limit(const T1 &limit,const T2 &value)
{
return assert_limit<T1,T2,safe>(limit,value);
}
}
#endif
and Operators.hpp:
//
// Operators.hpp
//
// September 27 2007 : Compiles OK.
//
// Defines operators in namespace 'STBase'. Used by real_t and safeT.
//
#ifndef __OPERATORS_HPP
#define __OPERATORS_HPP
#include "Assertions.hpp"
#include "../Utilities/Error.hpp"
namespace STBase
{
// Namespace-level binary sum of lhs and rhs, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> sum(const safeT<T1> &lhs,const T2 &rhs)
{
safeT<T1>copy(lhs.value() + assert_type<T2,T1>(rhs));
return copy;
}
// Namespace-level binary sum of lhs and rhs, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> sum(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
safeT<T1>copy(lhs.value() + assert_type<T2,T1>(rhs.value()));
return copy;
}
// Namespace-level binary difference with rhs, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> difference(const safeT<T1> &lhs,const T2 &rhs)
{
safeT<T1>copy(lhs.value() - assert_type<T2,T1>(rhs));
return copy;
}
// Namespace-level binary difference of lhs and rhs, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> difference(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
safeT<T1>copy(lhs.value() - assert_type<T2,T1>(rhs.value()));
return copy;
}
// Namespace-level binary product of lhs and rhs, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> product(const safeT<T1> &lhs,const T2 &rhs)
{
safeT<T1>copy(lhs.value() * assert_type<T2,T1>(rhs));
return copy;
}
// Namespace-level binary product of lhs and rhs, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> product(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
safeT<T1>copy(lhs.value() * assert_type<T2,T1>(rhs.value()));
return copy;
}
// Namespace-level binary quotient of lhs and rhs, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> quotient(const safeT<T1> &lhs,const T2 &rhs)
{
if (rhs == 0)
{
STUtility::error error_cond("Divide by zero");
error_cond.die();
}
safeT<T1>copy(lhs.value() / assert_type<T2,T1>(rhs));
return copy;
}
// Namespace-level binary quotient of lhs and rhs, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> quotient(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
if (rhs.value() == 0)
{
STUtility::error error_cond("Divide by zero");
error_cond.die();
}
safeT<T1>copy(lhs.value() / assert_type<T2,T1>(rhs.value()));
return copy;
}
// Namespace-level binary modulus of lhs and rhs, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> modulus(const safeT<T1> &lhs,const T2 &rhs)
{
safeT<T1>copy(lhs.value() % assert_type<T2,T1>(rhs));
return copy;
}
// Namespace-level binary modulus of lhs and rhs, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> modulus(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
safeT<T1>copy(lhs.value() % assert_type<T2,T1>(rhs.value()));
return copy;
}
// Namespace-level binary bitwise AND, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> bit_and(const safeT<T1> &lhs,const T2 &rhs)
{
safeT<T1>copy(lhs.value() & assert_type<T2,T1>(rhs));
return copy;
}
// Namespace-level binary bitwise AND, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> bit_and(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
safeT<T1>copy(lhs.value() & assert_type<T2,T1>(rhs.value()));
return copy;
}
// Namespace-level binary bitwise OR, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> bit_or(const safeT<T1> &lhs,const T2 &rhs)
{
safeT<T1>copy(lhs.value() | assert_type<T2,T1>(rhs));
return copy;
}
// Namespace-level binary bitwise OR, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> bit_or(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
safeT<T1>copy(lhs.value() | assert_type<T2,T1>(rhs.value()));
return copy;
}
// Namespace-level binary bitwise XOR, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> bit_xor(const safeT<T1> &lhs,const T2 &rhs)
{
safeT<T1>copy(lhs.value() ^ assert_type<T2,T1>(rhs));
return copy;
}
// Namespace-level binary bitwise XOR, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> bit_xor(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
safeT<T1>copy(lhs.value() ^ assert_type<T2,T1>(rhs.value()));
return copy;
}
// Namespace-level binary bitwise RIGHT SHIFT, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> bit_shift_right(const safeT<T1> &lhs,const T2 &rhs)
{
safeT<T1>copy(lhs.value() >> assert_type<T2,T1>(rhs));
return copy;
}
// Namespace-level binary bitwise RIGHT SHIFT, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> bit_shift_right(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
safeT<T1>copy(lhs.value() >> assert_type<T2,T1>(rhs.value()));
return copy;
}
// Namespace-level binary bitwise LEFT SHIFT, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> bit_shift_left(const safeT<T1> &lhs,const T2 &rhs)
{
safeT<T1>copy(lhs.value() << assert_type<T2,T1>(rhs));
return copy;
}
// Namespace-level binary bitwise LEFT SHIFT, assert_type.
template <typename T1,typename T2,template<typename T3>class safeT>
const safeT<T1> bit_shift_left(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
safeT<T1>copy(lhs.value() << assert_type<T2,T1>(rhs.value()));
return copy;
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntEqual(const safeT<T1> &lhs,const T2 &rhs)
{
return (lhs.value() == assert_type<T2,T1>(rhs));
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntEqual(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
return (lhs.value() == assert_type<T2,T1>(rhs.value()));
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntNotEqual(const safeT<T1> &lhs,const T2 &rhs)
{
return (lhs.value() != assert_type<T2,T1>(rhs));
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntNotEqual(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
return (lhs.value() != assert_type<T2,T1>(rhs.value()));
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntGreater(const safeT<T1> &lhs,const T2 &rhs)
{
return (lhs.value() > assert_type<T2,T1>(rhs));
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntGreater(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
return (lhs.value() > assert_type<T2,T1>(rhs.value()));
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntGreaterOrEqual(const safeT<T1> &lhs,const T2 &rhs)
{
return (lhs.value() >= assert_type<T2,T1>(rhs));
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntGreaterOrEqual(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
return (lhs.value() >= assert_type<T2,T1>(rhs.value()));
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntLess(const safeT<T1> &lhs,const T2 &rhs)
{
return (lhs.value() < assert_type<T2,T1>(rhs));
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntLess(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
return (lhs.value() < assert_type<T2,T1>(rhs.value()));
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntLessOrEqual(const safeT<T1> &lhs,const T2 &rhs)
{
return (lhs.value() <= assert_type<T2,T1>(rhs));
}
// Namespace-level binary integer boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isIntLessOrEqual(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
return (lhs.value() <= assert_type<T2,T1>(rhs.value()));
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealEqual(const safeT<T1> &lhs,const T2 &rhs)
{
// Is value at or within tolerance band?
return ((lhs.value() <= rhs*real_limits<T1>::upper_bound) && (lhs.value() >= rhs*real_limits<T1>::lower_bound));
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealEqual(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
// Is value at or within tolerance band?
return ((lhs.value() <= rhs.value()*real_limits<T1>::upper_bound) && (lhs.value() >= rhs.value()*real_limits<T1>::lower_bound));
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealNotEqual(const safeT<T1> &lhs,const T2 &rhs)
{
// Is value outside tolerance band?
return ((lhs.value() > rhs*real_limits<T1>::upper_bound) && (lhs.value() < rhs*real_limits<T1>::lower_bound));
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealNotEqual(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
// Is value outside tolerance band?
return ((lhs.value() > rhs.value()*real_limits<T1>::upper_bound) && (lhs.value() < rhs.value()*real_limits<T1>::lower_bound));
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealGreater(const safeT<T1> &lhs,const T2 &rhs)
{
// Is value above upper_bound?
return (lhs.value() > rhs*real_limits<T1>::upper_bound);
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealGreater(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
// Is value above upper_bound?
return (lhs.value() > rhs.value()*real_limits<T1>::upper_bound);
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealGreaterOrEqual(const safeT<T1> &lhs,const T2 &rhs)
{
// Is value above or at upper_bound?
return (lhs.value() >= rhs*real_limits<T1>::upper_bound);
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealGreaterOrEqual(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
// Is value above or at upper_bound?
return (lhs.value() >= rhs.value()*real_limits<T1>::upper_bound);
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealLess(const safeT<T1> &lhs,const T2 &rhs)
{
// Is value below lower_bound?
return (lhs.value() < rhs*real_limits<T1>::lower_bound);
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealLess(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
// Is value below lower_bound?
return (lhs.value() < rhs.value()*real_limits<T1>::lower_bound);
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealLessOrEqual(const safeT<T1> &lhs,const T2 &rhs)
{
// Is value at or below lower_bound?
return (lhs.value() <= rhs*real_limits<T1>::lower_bound);
}
// Namespace-level binary real boolean test.
template <typename T1,typename T2,template<typename T3>class safeT>
const bool isRealLessOrEqual(const safeT<T1> &lhs,const safeT<T2> &rhs)
{
// Is value at or below lower_bound?
return (lhs.value() <= rhs.value()*real_limits<T1>::lower_bound);
}
}
#endif
[Edited by - random_thinker on September 27, 2007 5:25:50 PM]
--random_thinkerAs Albert Einstein said: 'Imagination is more important than knowledge'. Of course, he also said: 'If I had only known, I would have been a locksmith'.