dnl (don't we all *love* M4?)...
GINACLIB_MAJOR_VERSION=1
-GINACLIB_MINOR_VERSION=0
-GINACLIB_MICRO_VERSION=4
-GINACLIB_INTERFACE_AGE=2
-GINACLIB_BINARY_AGE=4
+GINACLIB_MINOR_VERSION=1
+GINACLIB_MICRO_VERSION=0
+GINACLIB_INTERFACE_AGE=0
+GINACLIB_BINARY_AGE=0
GINACLIB_VERSION=$GINACLIB_MAJOR_VERSION.$GINACLIB_MINOR_VERSION.$GINACLIB_MICRO_VERSION
AC_SUBST(GINACLIB_MAJOR_VERSION)
// non-virtual functions in this class
//////////
-/** Cast the relational into a boolean, mainly for evaluation within an
+relational::safe_bool relational::make_safe_bool(bool cond) const
+{
+ return cond? &safe_bool_helper::nonnull : 0;
+}
+
+/** Cast the relational into a boolean, mainly for evaluation within an
* if-statement. Note that (a<b) == false does not imply (a>=b) == true in
* the general symbolic case. A false result means the comparison is either
* false or undecidable (except of course for !=, where true means either
* unequal or undecidable). */
-relational::operator bool() const
+relational::operator relational::safe_bool() const
{
const ex df = lh-rh;
if (!is_ex_exactly_of_type(df,numeric))
// cannot decide on non-numerical results
- return o==not_equal ? true : false;
-
+ return o==not_equal ? make_safe_bool(true) : make_safe_bool(false);
+
switch (o) {
case equal:
- return ex_to<numeric>(df).is_zero();
+ return make_safe_bool(ex_to<numeric>(df).is_zero());
case not_equal:
- return !ex_to<numeric>(df).is_zero();
+ return make_safe_bool(!ex_to<numeric>(df).is_zero());
case less:
- return ex_to<numeric>(df)<_num0;
+ return make_safe_bool(ex_to<numeric>(df)<_num0);
case less_or_equal:
- return ex_to<numeric>(df)<=_num0;
+ return make_safe_bool(ex_to<numeric>(df)<=_num0);
case greater:
- return ex_to<numeric>(df)>_num0;
+ return make_safe_bool(ex_to<numeric>(df)>_num0);
case greater_or_equal:
- return ex_to<numeric>(df)>=_num0;
+ return make_safe_bool(ex_to<numeric>(df)>=_num0);
default:
throw(std::logic_error("invalid relational operator"));
}
virtual ex rhs(void) const;
// non-virtual functions in this class
-public:
- operator bool(void) const;
+private:
+ // For conversions to boolean, as would be used in an if conditional,
+ // implicit conversions from bool to int have a large number of
+ // undesirable side effects. The following safe_bool type enables
+ // use of relational objects in conditionals without those side effects
+ struct safe_bool_helper {
+ void nonnull() {};
+ };
+
+ typedef void (safe_bool_helper::*safe_bool)();
+ safe_bool make_safe_bool(bool) const;
+
+public:
+ operator safe_bool(void) const;
+ safe_bool operator!(void) const;
+
// member variables
protected:
return obj.tinfo()==TINFO_relational;
}
+// inlined functions for efficiency
+inline relational::safe_bool relational::operator!() const
+{
+ return make_safe_bool(!static_cast<bool>(*this));
+}
+
} // namespace GiNaC
#endif // ndef __GINAC_RELATIONAL_H__