Muhammad
Muhammad

Reputation: 1655

more than one operator matches these operands

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?

Upvotes: 1

Views: 11212

Answers (3)

jerry
jerry

Reputation: 2611

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);

Upvotes: 0

mjfgates
mjfgates

Reputation: 3431

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.

Upvotes: 0

Seth Carnegie
Seth Carnegie

Reputation: 75130

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.

Upvotes: 1

Related Questions