90

At the top of my file I have

#define AGE "42"

Later in the file I use ID multiple times including some lines that look like

std::string name = "Obama";
std::string str = "Hello " + name + " you are " + AGE + " years old!";
str += "Do you feel " + AGE + " years old?";

I get the error:

"error: invalid operands of types ‘const char [35]’ and ‘const char [2]’ to binary ‘operator+’"

on line 3. I did some research and found it was because of how C++ was treating the different strings and was able to fix it by changing "AGE" to "string(AGE)." However, I accidentally missed one of the instances until today and was wondering why the compiler wasn't complaining even though I still had an instance where it was just "AGE".

Through some trial and error I found that I only need string(AGE) on lines where I don't concatenate another string that was created in the function body.

My questions is "what is going on in the background that C++ doesn't like concatenating a string with a string put there by the preprocessor unless you are also concatenating string that you defined in the function."

user3840170
  • 26,597
  • 4
  • 30
  • 62
janovak
  • 1,531
  • 2
  • 12
  • 22
  • 1
    Thank you for your explanations. Even though I decided to get rid of the macro I am glad I know the "why." – janovak May 29 '14 at 15:17

6 Answers6

131

Consider this:

std::string str = "Hello " + "world"; // bad!

Both the rhs and the lhs for operator + are char*s. There is no definition of operator + that takes two char*s (in fact, the language doesn't permit you to write one). As a result, on my compiler this produces a "cannot add two pointers" error (yours apparently phrases things in terms of arrays, but it's the same problem).

Now consider this:

std::string str = "Hello " + std::string("world"); // ok

There is a definition of operator + that takes a const char* as the lhs and a std::string as the rhs, so now everyone is happy.

You can extend this to as long a concatenation chain as you like. It can get messy, though. For example:

std::string str = "Hello " + "there " + std::string("world"); // no good!

This doesn't work because you are trying to + two char*s before the lhs has been converted to std::string. But this is fine:

std::string str = std::string("Hello ") + "there " + "world"; // ok

Because once you've converted to std::string, you can + as many additional char*s as you want.

If that's still confusing, it may help to add some brackets to highlight the associativity rules and then replace the variable names with their types:

((std::string("Hello ") + "there ") + "world");
((string + char*) + char*)

The first step is to call string operator+(string, char*), which is defined in the standard library. Replacing those two operands with their result gives:

((string) + char*)

Which is exactly what we just did, and which is still legal. But try the same thing with:

((char* + char*) + string)

And you're stuck, because the first operation tries to add two char*s.

Moral of the story: If you want to be sure a concatenation chain will work, just make sure one of the first two arguments is explicitly of type std::string.

dlf
  • 9,045
  • 4
  • 32
  • 58
  • I had a similar code `throw out_of_range("ModuleName:: " __FUNCTION__ ": Exception message");` and it compiled fine with VS2010. I am not sure why or how that happened. But when I tried to compile it with gcc I got error. I had to finally do something like `throw out_of_range(string("ModuleName:: ") + __FUNCTION__ + ": Exception message");` – sabertooth1990 Mar 10 '16 at 12:38
  • 1
    @sabertooth1990 gcc isn't my compiler, but from a quick look at its documentation, it appears that the type of the `__FUNCTION__` extension is `char[]`. You can concatenate string literals together by writing them all in a row, but that doesn't work with arrays or pointers. vcc must treat it as a literal. – dlf Mar 10 '16 at 13:15
  • 1
    It is also because the `operator+` is left-associative. So as the following expression `"Do you feel " + "42" + " years old?"` becomes `("Do you feel " + "42") + " years old?"` and the compiler cannot find a method that can handle this. Whereas when there's an `std::string` in any of the operands (LHS or RHS to the `+`) then the `operator+` has an overloaded method to handle the string literal. – g13n Mar 20 '16 at 16:55
  • 1
    I don't like to imply the left-hand string is any different from the other strings, so I start with an empty string and concatenate all you want after it. `std::string value = std::string() + "Happy Birthday! You are now " + AGE + " years old";` – nathanfranke Apr 20 '20 at 19:22
18

AGE is defined as "42" so the line:

str += "Do you feel " + AGE + " years old?";

is converted to:

str += "Do you feel " + "42" + " years old?";

Which isn't valid since "Do you feel " and "42" are both const char[]. To solve this, you can make one a std::string, or just remove the +:

// 1.
str += std::string("Do you feel ") + AGE + " years old?";

// 2.
str += "Do you feel " AGE " years old?";
clcto
  • 9,530
  • 20
  • 42
5

In line 2, there's a std::string involved (name). There are operations defined for char[] + std::string, std::string + char[], etc. "Hello " + name gives a std::string, which is added to " you are ", giving another string, etc.

In line 3, you're saying

char[] + char[] + char[]

and you can't just add arrays to each other.

Paul Roub
  • 36,322
  • 27
  • 84
  • 93
5

You cannot concatenate raw strings like this. operator+ only works with two std::string objects or with one std::string and one raw string (on either side of the operation).

std::string s("...");
s + s; // OK
s + "x"; // OK
"x" + s; // OK
"x" + "x" // error

The easiest solution is to turn your raw string into a std::string first:

"Do you feel " + std::string(AGE) + " years old?";

Of course, you should not use a macro in the first place. C++ is not C. Use const or, in C++11 with proper compiler support, constexpr.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
4

In this particular case, an even simpler fix would be to just get rid of the "+" all together because AGE is a string literal and what comes before and after are also string literals. You could write line 3 as:

str += "Do you feel " AGE " years old?";

This is because most C/C++ compilers will concatenate string literals automatically. The above is equivalent to:

str += "Do you feel " "42" " years old?";

which the compiler will convert to:

str += "Do you feel 42 years old?";

djulien
  • 141
  • 1
  • 2
0

I had the same problem in my code. I was concatenating a string to create a string. Below is the part of code.

int scannerId = 1;
std:strring testValue;
strInXml = std::string(std::string("<inArgs>" \
                        "<scannerID>" + scannerId) + std::string("</scannerID>" \
                        "<cmdArgs>" \
                        "<arg-string>" + testValue) + "</arg-string>" \
                        "<arg-bool>FALSE</arg-bool>" \
                        "<arg-bool>FALSE</arg-bool>" \
                        "</cmdArgs>"\
                        "</inArgs>");
Dig The Code
  • 658
  • 2
  • 15
  • 32