Thanks Sneftel..I've changed and recompiled and it works. What a compiler hack this is; just an int, and I thought that any integer would do, because, as I understand, only integral types can use increment operators anyway.
I've used this int_t (safe integer) class pretty extensively over the last day or so and it works quite well. Now I'm trying to push it to the bit level, thinking that this will be the ultimate test of the type...the code follows:
// int_t safe integer typetemplate<typename intType>class int_t{public: int_t() : value_(0) { } int_t(const intType arg) : value_(arg) { } int_t(const int_t<intType>& arg) : value_(arg.value_) { } ~int_t() { } int_t operator=(const int_t<intType> arg) { value_ = arg.value_; return *this; } int_t operator=(const intType arg) { value_ = arg; return *this; } int_t operator+(const intType arg) const { return (int_t<intType>(value_ + arg)); } int_t operator+(const int_t<intType> arg) const { return (int_t<intType>(value_ + arg.value_)); } int_t operator-(const intType arg) const { return (int_t<intType>(value_ - arg)); } int_t operator-(const int_t<intType> arg) const { return (int_t<intType>(value_ - arg.value_)); } int_t operator*(const intType arg) const { return (int_t<intType>(value_ * arg)); } int_t operator*(const int_t<intType> arg) const { return (int_t<intType>(value_ * arg.value_)); } int_t operator/(const intType arg) const { if (arg == 0) { // Custom error class... STUtility::error error_cond("Divide by zero"); error_cond.die(); } return (int_t<intType>(value_ / arg)); } int_t operator/(const int_t<intType> arg) const { if (arg.value_ == 0) { // Custom error class... STUtility::error error_cond("Divide by zero"); error_cond.die(); } return (int_t<intType>(value_ / arg.value_)); } int_t operator%(const intType arg) const { return (int_t<intType>(value_ % arg)); } int_t operator%(const int_t<intType> arg) const { return (int_t<intType>(value_ % arg.value_)); } int_t operator&(const intType arg) const { return (int_t<intType>(value_ & arg)); } int_t operator&(const int_t<intType> arg) const { return (int_t<intType>(value_ & arg.value_)); } int_t operator|(const intType arg) const { return (int_t<intType>(value_ | arg)); } int_t operator|(const int_t<intType> arg) const { return (int_t<intType>(value_ | arg.value_)); } int_t operator^(const intType arg) const { return (int_t<intType>(value_ ^ arg)); } int_t operator^(const int_t<intType> arg) const { return (int_t<intType>(value_ ^ arg.value_)); } int_t operator~() const { return (int_t<intType>(~value_)); } int_t operator<<(const intType arg) const { return (int_t<intType>(value_ << arg)); } int_t operator<<(const int_t<intType> arg) const { return (int_t<intType>(value_ << arg.value_)); } int_t operator>>(const intType arg) const { return (int_t<intType>(value_ >> arg)); } int_t operator>>(const int_t<intType> arg) const { return (int_t<intType>(value_ >> arg.value_)); } // Increment. int_t operator++() { ++value_; return *this; } // Post increment. int_t operator++(int) { int_t<intType>copy(*this); ++value_; return copy; } // Decrement. int_t operator--() { --value_; return *this; } // Post decrement. int_t operator--(int) { int_<intType>copy(*this); --value_; return copy; } int_t operator+=(const intType arg) { value_ = value_ + arg; return *this; } int_t operator+=(const int_t<intType> arg) { value_ = value_ + arg.value_; return *this; } int_t operator-=(const intType arg) { value_ = value_ - arg; return *this; } int_t operator-=(const int_t<intType> arg) { value_ = value_ - arg.value_; return *this; } int_t operator*=(const intType arg) { value_ = value_ * arg; return *this; } int_t operator*=(const int_t<intType> arg) { value_ = value_ * arg.value_; return *this; } int_t operator/=(const intType arg) { if (arg == 0.0) { // Custom error class... STUtility::error error_cond("Divide by zero"); error_cond.die(); } value_ = value_ / arg; return *this; } int_t operator/=(const int_t<intType> arg) { if (arg.value_ == 0.0) { // Custom error class... STUtility::error error_cond("Divide by zero"); error_cond.die(); } value_ = value_ / arg.value_; return *this; } intType value() { return value_; } bool operator==(const intType arg) const { return (value_ == arg); } bool operator==(const int_t<intType> arg) const { return (value_ == arg.value_); } bool operator!=(const intType arg) const { return (value_ != arg); } bool operator!=(const int_t<intType> arg) const { return (value_ != arg.value_); } bool operator>=(const intType arg) const { return (value_ >= arg); } bool operator>=(const int_t<intType> arg) const { return (value_ >= arg.value_); } bool operator>(const intType arg) const { return (value_ > arg); } bool operator>(const int_t<intType> arg) const { return (value_ > arg.value_); } bool operator<=(const intType arg) const { return (value_ <= arg); } bool operator<=(const int_t<intType> arg) const { return (value_ <= arg.value_); } bool operator<(const intType arg) const { return (value_ < arg); } bool operator<(const int_t<intType> arg) const { return (value_ < arg.value_); } static intType min() { return std::numeric_limits<intType>::min(); } static intType max() { return std::numeric_limits<intType>::max(); } private: intType value_; operator intType() const { return value_; }};// ostream operator for int_ttemplate<typename intType>std::ostream & operator<<(std::ostream & out, int_t<intType> arg){ return ( out << arg.value() ); }// istream operator for int_ttemplate<typename intType>std::istream & operator>>(std::istream & in, int_t<intType> arg){ return ( in >> arg.value() ); }
I'm now trying to see if it can be used for number generators, and this is where I'm starting to have problems. Some usage code follows and this just is not working yet, because it is mixing different int_t types, and the conversion behaviour at this moment is completely locked.
// The main generator method definition...this is based upon code from Marsaglia (2003).// safe_intu32 is a typedef for int_t<unsigned long>// safe_intu64 is a typedef for int_t<unsigned long long>// types are:// safe_intu32 i_,c_,x_,r_// safe_intu64 a_,t_// std::vector<safe_intu32> Q_//inline STBase::safe_intu32 STRandom::G0064::next(){ i_ = (i_ + 1)&4095; // Error, ambiguous conversion t_ = a_ * Q_[i_]+ c_; // Error, ambiguous overload operator * c_ = (t_ >> 32); // Error, ambiguous conversion x_ = t_ + c_; // Error, ambiguous overload operator + if (x_ < c_) // OK here { x_++; // Now this is OK...thanks! c_++; // Ditto. } return (Q_[i_] = r_ - x_); // Some problem here. }
The rest of these error seem to be related to the way that the compiler is interpreting the types and their conversion, and my first thought is to handle this problem through specialization and overloading conversion/assignment. Another approach could be to introduce a type conversion behaviour that is used by this base class.
--random
PS If this idea were not crazy enough, I've also introduced a 'real_t' class template that uses tolerances as a proportion of magnitude (as set in the real_limits struct) for boolean operations. It was actually much easier to implement than int_t.
Edit...looking at the code of Marsaglia above, the increment operators used should be pre- rather than post- anyway!
[Edited by - random_thinker on September 18, 2007 4:26:52 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'.