C++ operator types implicit conversion

I have a String class defined as:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class String
{
public:
	String();
	
	//[...]
	
	//These methods concatenate a String with a number
	String& operator+=(const int rhs) { return this->append(std::to_string(rhs).c_str()); }
	String& operator+(const int rhs) { return (*this) += rhs; }

	
	String& operator+=(const float rhs) { return this->append(std::to_string(rhs).c_str()); }
	String& operator+(const float rhs) { return (*this) += rhs; }
	
	//[...]
};


but when I try to do:

String s = "value = ";
int i = 3;
String s2 = s + i;

I get:

1>------ Build started: Project: (...), Configuration: Debug Win32 ------
1>  TestMain.cpp
1>(...): error C2593: 'operator +' is ambiguous
1>          (...): could be 'WPL::String &WPL::String::operator +(const WPL::Real)'
1>          (...): or       'WPL::String &WPL::String::operator +(const WPL::Int)'
1>          (...): or       'WPL::String &WPL::String::operator +(const char *)'
1>          (...): or       'WPL::String &WPL::String::operator +(const WPL::String &)'
1>          while trying to match the argument list '(WPL::String, WPL::UInt32)'
1>  String.cpp
1>(...): error C2593: 'operator +' is ambiguous
1>          (...): could be 'WPL::String &WPL::String::operator +(const WPL::Real)'
1>          (...): or       'WPL::String &WPL::String::operator +(const WPL::Int)'
1>          (...): or       'WPL::String &WPL::String::operator +(const char *)'
1>          (...): or       'WPL::String &WPL::String::operator +(const WPL::String &)'
1>          while trying to match the argument list '(WPL::String, WPL::UInt32)'
1>  Array.cpp
1>(...): error C2593: 'operator +' is ambiguous
1>          (...): could be 'WPL::String &WPL::String::operator +(const WPL::Real)'
1>          (...): or       'WPL::String &WPL::String::operator +(const WPL::Int)'
1>          (...): or       'WPL::String &WPL::String::operator +(const char *)'
1>          (...): or       'WPL::String &WPL::String::operator +(const WPL::String &)'
1>          while trying to match the argument list '(WPL::String, WPL::UInt32)'
1>  Generating Code...
1>  Compiling...
1>  WPLException.cpp
1>  Generating Code...
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


and intellisense gives me the error:
	IntelliSense: more than one operator "+" matches these operands:
            function "WPL::String::operator+(WPL::Int rhs)"
            function "WPL::String::operator+(WPL::Real rhs)"
            operand types are: WPL::String + WPL::UInt32


I can understand that i gets casted into a float by the compiler and that's why the error occurs, but is there any way of preventing the compiler from doing that?


Last edited on
Anyone?
You are omitting important code. The code you provided will work fine after filling in the blanks:

http://ideone.com/hWSfGL


Judging from the error log, I can only guess that:

1) You are not actually using an int (that is, 'i' in your example is some other type)
or
2) You do not actually have an overload of + that takes an int as a param.


But it's impossible to know for sure. If you could post code that actually reproduces the problem, then I could see what you're doing wrong.




On a side note

Your + operator is wrong, as it will modify 'this':

String& operator+(const float rhs) { return (*this) += rhs; }

You should not be doing *this += from the + operator -- as you will be appending to the 'this' string, which is not expected behavior.

In fact... all of your + operators should be const to prevent this kind of mistake:

String& operator+(const float rhs) const { ... }
I am sorry, the actual code that gives that error is something like this:

1
2
3
4
5
6
7
8
9
10
typedef unsigned long int UInt32;

//...

class SomeClass : SomeOtherClass
{
public:
	SomeClass(UInt32 i) : SomeOtherClass(String("i = ") + i) { }
	virtual ~SomeClass() {}
};


also I fixed my code as far as the operator+ is concerned:
note that operator= copies the internal c-string from one object to another and does not simply point to the original memory
1
2
3
4
5
6
7
8
9
10
11
12
13
class String
{
	//...
	
	String& operator+=(const int rhs) { return this->append(std::to_string(rhs).c_str()); }
	String& operator+(const int rhs) const { String s = (*this); return s += rhs; }

	String& operator+=(const float rhs) { return this->append(std::to_string(rhs).c_str()); }
	String& operator+(const float rhs) const { String s = (*this);  return s += rhs; }
	
	//...
	
}; //class String	 


I have also seen this syntax. Does it have any advantage over my version of operator+?
friend String operator+(String& lhs, const Int rhs) { return lhs += rhs; }
Last edited on
Okay this makes more sense.

You are giving the + operator a UInt32 as a rhs argument.
However, you do not have any version of the + operator that takes a UInt32. So the compiler has to convert that UInt32 to another type.

And it gets confused, because it could convert it to int or to float, and it doesn't know which one you want it to do. Hence, the call is ambiguous.

Your solution here is:
1) Add an overload to handle UInt32
or
2) Explicitly cast your UInt32 to something else:

1
2
3
SomeClass(UInt32 i) : SomeOtherClass(String("i = ") + static_cast<int>(i)) { }
// or
SomeClass(int i) : SomeOtherClass(String("i = ") + i) { }





Also note:

Your + operator is still broken because you are returning a reference to a temporary object. You should return by value:
1
2
String& operator+(const float rhs) const { String s = (*this);  return s += rhs; } // <- bad, returning a temporary by reference
String  operator+(const float rhs) const { String s = (*this);  return s += rhs; } // <- good 




I have also seen this syntax. Does it have any advantage over my version of operator+?


Not really. It's just a different style -- although I think it might make a minor difference with how the compiler looks up the operator -- I don't know, I'm fuzzy on the details.. it's really obscure and hardly ever matters.

So it's basically the same thing.

Although that + operator is also broken because, again, it's behaving like += and modifying the lhs param.
thanks for the help.
as for my operator+:
String& operator+(const float rhs) const { String s = (*this); return s += rhs; }
typing error, sorry.
in my code it is as you promted:
String operator+(const float rhs) const { String s = (*this); return s += rhs; }
Topic archived. No new replies allowed.