I have a class called Base, which is basically just a double with a bunch of member functions and a long list of operators to make it behave like a number. Other than that, I also have a Type() member which returns an integer.
I want to keep the Base type because it makes my code more readable and distinguishes the base type from an ordinary double, but I also don't like having to overload every single operators, as this is tedious. Ideally, I'd use enum Base double and then declare a Base member function Type() to get the integer, but this isn't legal in c++, is it?
So how can I easily achieve double-like functionality of my class while having a simple member function that returns an int?
P.S. the Type() function is not a simple cast or rounding, it's a complex function that I'd like to keep as a member if possible for clarity.
So if I can cast to double and from double, then when I write something like this:
1 2 3 4
Base A = 1.0; // cast from double to Base
Base B = 2.0; // case from double to base
A += B; // no cast to/from double, and no operator overload - error?
Will that work? How would that last line function?
JLBorges, thank you for that example. My issue is then, as with kbw's example, is that as far as I understand this will fail:
1 2 3 4 5 6 7 8
real r = 7.8;
real s = 23.6;
// no implicit conversion and no operator overload in the following:
r += s;
r *= s;
r = r/s;
//etc...
kbw:
Right, but you may not need one. Do you have an example of one you think you need?
Well as the class stores a double, I was thinking of simply typedefing something like this:
typedefdouble Base
and then creating a custom global function:
int getType(Base&);
which returns the type value based on the input. However, I am trying to avoid situations where I have global functions that only operate on a single type. Since a typedef member function isn't possible, can I overload implicit conversion, so that I could then do this:
1 2 3 4
typedefdouble Base;
Base my_base = 1.1;
// define implicit conversion overload
int type_of_base = my_base; // not a simple removal of decimal values
struct real
{
real( double v = 0.0 ) : value(v) {}
// implicit conversions
operatordouble& () { return value ; }
operatordouble () const { return value ; }
double* operator& () { return &value ; }
constdouble* operator& () const { return &value ; }
// other operations
bool is_nan() const { return value != value ; }
// etc.
private: double value ;
};
#include <iostream>
int main()
{
real r = 7.8;
real s = 23.6;
// the implicit conversion to double& in conjunction with
// the implicit conversion via constructor will take care of these:
r += s ; std::cout << r << '\n' ; // 31.4
r *= s ; std::cout << r << '\n' ; // 741.04
r = r/s ; std::cout << r << '\n' ; // 31.4
// remove the conversion to long long and these too are fine
// (we avoid the anbiguity - real to double or real to long long)
// (but we lose the range check for conversion to an integral value)
const real t = 6.7 ;
r += t ; std::cout << r << '\n' ; // 38.1
r *= t ; std::cout << r << '\n' ; // 255.27
r = r/t ; std::cout << r << '\n' ; // 38.1
int i = r ; std::cout << i << '\n' ; // 38
}
Cool, thanks, that's exactly what I wanted. Just for the sake of my understanding can you please clarify how the compiler knows to cast to double and then back to "real" in this:
#include <iostream>
#include <typeinfo>
#include <cassert>
int main()
{
real r = 7.8;
real s = 23.6;
const real t = 6.7 ;
{
// A, B and C are equivalent
r += t ; // A
static_cast<double&>(r) += static_cast<double>(t) ; // B
r.operatordouble&() += t.operatordouble() ; // C
assert( typeid( r += t ) == typeid( double& ) ) ;
}
{
// A, B and copy-elided(C1,C2,C3,C4) are equivalent
r = s + t ; // A
r = real( static_cast<double&>(s) + static_cast<double>(t) ) ; // B
double& ss = s.operatordouble&() ; // C1
double tt = t.operatordouble() ; // C2
real rr( ss/tt ) ; // C3
r = rr ; // C4
assert( typeid( r = s/t ) == typeid( real& ) ) ;
}
}
So does the compiler know to cast to reference to double in "A" because it sees that a) there is no "+=" for the real class, b) there is a "+=" operator for the double primitive and c) the real class can implicit cast to double?
Would the answer be 7.8+23.6 (cast to double) or 7.8+23 (cast to int)? How would it know which one to do, since the "+=" operator exists for both int and double primitives?
Sorry for the million questions, I'm just really trying to understand what's going on...
#include <iostream>
#include <fstream>
struct real
{
real( double v = 0.0 ) : value(v) {}
// implicit conversions
operatordouble& () { return value ; }
operatordouble () const { return value ; }
//operator int& () { return value ; } // won't compile
operatorint () const { return value ; }
private: double value ;
};
int main()
{
real r = 7.8;
real s = 23.6;
r += s; // this is fine; (double&)s
const real& t = 6.7 ;
r += t ; // *** error: this is ambiguous; double(t) or int(t)
}
You should not be having conversion operators for any other standard arithmetic type other than double; an implicit conversion from, say, real => int would be still possible, since a user defined conversion and a standard conversion can be combined.
real => int would be real => double (user defined), followed by double => int (standard)