Suppose we have next code:
struct int64
{
long long value;
int64() : value(0) {}
int64(signed char i8) : value(i8) {}
int64(unsigned char u8) : value(u8) {}
int64(short i16) : value(i16) {}
int64(unsigned short u16) : value(u16) {}
int64(int i32) : value(i32) {}
int64(unsigned u32) : value(u32) {}
int64(long long i64) : value(i64) {}
int64(unsigned long long u64) : value(u64) {}
int64(const int64& i64) : value(i64.value) {}
int64& operator+=(const int64& rhs) { return value += rhs.value, *this; }
int64& operator-=(const int64& rhs) { return value -= rhs.value, *this; }
friend int64 operator+(const int64& lhs, const int64& rhs) { return int64(lhs) += rhs; }
friend int64 operator-(const int64& lhs, const int64& rhs) { return int64(lhs) -= rhs; }
operator char() const { return (char)value; }
operator short() const { return (short)value; }
operator int() const { return (int)value; }
operator long long()开发者_如何学编程 const { return value; }
};
when compiling the this code:
int64 q = 500;
int64 m = q + 1024;
an error occurred because there is 4 similar conversion available to 1024
and one for q
to integer type, to solve this problem, i removed the operator XX
from the int64
and added the following code:
template <typename n>
operator n() const { return (n)value; }
now i can execute the following code:
int64 q = 500;
int64 m = q + 1024;
short r = q;
the template definition works with Visual C++
and GCC
compilers but Intel C++
compiler.
how can i write this conversion operators that work for those compilers?
You should write operator+
definitions for all the types you are supporting:
int64 operator+(int num) {
return int64(value + num);
}
int64 operator+(short num) {
...
}
...
You're adding an int
to an int64
and assigning the result to an int64
but it doesn't have a copy constructor so it's converting it to some integral type and trying to do some weirdness with all those conversion operators and constructors.
The trouble here is that if you provide both a constructor from a built-in type, and a conversion operator TO that same type, and then have an expression with both types, C++ can't really prioritize which way it's supposed to go. So, " myInt64Variable + 1024" could mean either " (int)myInt64Variable + 1024)" via the conversion-to-int operator, or " myInt64Variable + (int64)1024" via the constructor.
In my experience, the best way to handle this is to not provide the conversion operators, or if you must have them, to make a toInt() function or similar. Any conversion from your custom type to a built-in type is going to be a lossy one, or else why have the custom type at all?, and making people notice when they're performing a lossy conversion is a Good Thing.
Starting with C++11 (which had just been ratified when this question was asked), you can mark the conversions explicit
:
struct int64
{
// ...
explicit operator char() const { return (char)value; }
explicit operator short() const { return (short)value; }
explicit operator int() const { return (int)value; }
explicit operator long long() const { return value; }
};
This should work in the latest versions of all the major compilers (all the one's I've tested have sufficient C++11 support). You can also apply this to your templated conversion operator if you like, though I prefer the four non-templated conversions (plus, this crashed the version of ICC I tried it on!):
struct int64
{
// ...
template <typename n>
explicit operator n() const { return static_cast<n>(value); }
};
However, this means that you can't do short r = q;
. To me, that's a good thing, as the narrowing conversion really should be
short r = static_cast<short>(q);
精彩评论