4

I have this code:

#include <iostream>                     
using namespace std; 

int main()                  
{                                                                                    
       string name = "John ";                     
       int age = 32;         
       name += age;    
       cout << name << endl;
       return 0;                                          
}

The code compiles successfully but betrays at run time as it silently ignores the concatenation part and prints:

John

I know that we need to use stringstream for the task. But why does the above code compile? Because the following code:

#include <iostream>
using namespace std;                                                                 

int main()                       
{                                                                                    
       string name = "John ";                              
       int age = 55;                                    
       name = name + age;             
       cout << name << endl;      
       return 0;
} 

duly throws and error:

error: no match for ‘operator+’ in ‘name + age’

I know from Java that a += b is different from a = a + b as the former construct typecasts the result to the type of a. Reference. But I don't think this would matter in C++ as we can always do:

   int a = 1;                                                                       
   float f = 3.33;                                                                  
   a = a + f;

without worrying about a possible loss of precision warning unlike Java. Need citation for this in C++.

So now if we assume that name += age; expands to name = string (name + age); then also the code should not have compiled simply because name + age is not legal.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
KodingKid
  • 971
  • 9
  • 14
  • 5
    Are you sure it ignores the concatenation? I get `John 7`, which is what I'd expect since 55 is the ASCII value for `'7'`. – Mike Seymour Dec 04 '13 at 16:52
  • 2
    Also, your assumption is wrong. For class types, `a += b` is not equivalent to `a = a+b`. The first uses `operator+=`, the second uses `operator+` and `operator=`, and it's entirely up to the class writer how these operators are implemented. – Mike Seymour Dec 04 '13 at 16:55
  • True. But I knew that += for strings works like a + b. And yes it prints John 7. I had age = 32 on my machine. Typo. All's clear now. Thanks! – KodingKid Dec 04 '13 at 17:03
  • Without loss of precision? If a is an int, how is that going to happen? Seems like the .33 wont make it *to* the first operator. What you wrote is ‘a.operator=(a.+(f.operator int()))‘ – kfsone Dec 04 '13 at 17:08
  • I meant warning. Updating it. Thanks for pointing it out. – KodingKid Dec 04 '13 at 17:09
  • the 'The code compiles successfully but betrays at run time as it silently ignores the concatenation part and prints:' is still wrong, 32 is just ascii for a space. if you took the length of the string, you would see it grew by a character. – Stephan van den Heuvel Dec 04 '13 at 17:28

1 Answers1

11

You need to use the -Wconversion flag(It is not clear to me why this is not included in -Wall) also see the Options to Request or Suppress Warnings for more details. When I add that flag I see the following warning when using gcc:

 warning: conversion to 'char' from 'int' may alter its value [-Wconversion]
    name += age;  
         ^

and we can see that indeed operator += does support char and therefore the converted value is indeed being add to the end of name, it is not ignoring the operation at all. In C++ operator + for std::string is a different operator than operator +=.

In this specific case:

name += age;

would translate to something like this:

name.operator+=(static_cast<char>(age)) ;

and if we had a expression using operator + without an error like this one:

name = name + static_cast<char>( age );

would translate to:

operator+( name, static_cast<char>( age ) ) ;

The reason why this fails for operator + in your example is covered well in this answer, basically template functions won't perform conversions and so require an exact match with the possible exception of const/volatile qualifiers.

Update on Wconversion

gcc has a Wconversion Wiki with a FAQ, it is a bit dated but it does answer why this check is not included with the -Wall flag:

Implicit conversions are very common in C. This tied with the fact that there is no data-flow in front-ends (see next question) results in hard to avoid warnings for perfectly working and valid code. Wconversion is designed for a niche of uses (security audits, porting 32 bit code to 64 bit, etc.) where the programmer is willing to accept and workaround invalid warnings. Therefore, it shouldn't be enabled if it is not explicitly requested.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • And is a += b; expanded as a = (type of a) a + b; in C++ as it is done in Java? – KodingKid Dec 04 '13 at 17:16
  • @KodingKid assuming `a` is a *std::string* this will translate to `a.operator+=(b)` with a suitable type conversion for `b` if needed. – Shafik Yaghmour Dec 04 '13 at 17:24
  • @KodingKid No. When dealing with overloaded operators, `+=` and `+` are entirely unrelated, as far as the language is concerned. (Of course, any good programmer will always provide both if he provides one, with the expected semantic relationship.) – James Kanze Dec 04 '13 at 17:31
  • @KodingKid Also, I don't think Java defines it this way either. If I write `someComplicatedExpressionWithSideEffects += 'x'`, `someComplicatedExpressionWithSideEffects` will not be evaluated twice. – James Kanze Dec 04 '13 at 17:33
  • From Java docs, [http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.26.2] "A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once." – KodingKid Dec 04 '13 at 17:41
  • @KodingKid just keep in mind that *Java* and *C++* are very different in many ways and trying to understand *C++* through *Java* is probably not a good idea. – Shafik Yaghmour Dec 04 '13 at 17:51