1

I'm studying about the C++ library type string. I was looking into operation that the type can perform, among which are concatenation. I know that in C++ operators can be overloaded to suit class types needs,and I know that character string literals are const char arrays under the hood. So, I know that the string type defines a constructor that takes a string literal argument and converts it into a string, so that I can initialize a string using:

string s="hello!"

what happens here is an impicit conversion (through the constructor that takes a const char*) to string and then a copy initialization is performed (through the copy-constructor of string).

so far so good.. (correct me if I am getting something wrong so far)

Now, I know that I can concatenate two strings, or I can concatenate a string and a char literal (or vice versa) and a string and a string literal (so I suppose the first happens because there's an overloaded + operator that takes symmetrically a char and a string, the latter happens thanks to the overloaded + opeartor that concatenates two strings and the implicit conversion from const char* to string). My questions are:

1: why can't I concatenate two string literals? shouldn't the operator+ that takes two strings be called (and two implicit conversion performed from const char* to string) ?

string s="hi"+" there";

2: I tried to concatenate a char literal and a string literal (calling the operator+ that takes a char and a string) but I get only garbage in the resulting string, as the compiler doesn't mind, but the result is certainly not what I want.

string s='h'+"ello!";
cout<<s<<endl;

I get garbage out.If a operator+(char,const string&) exists it should be called after implicitly converting "ello" to string shouldn't it?

can you please explain?

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
Luca
  • 1,658
  • 4
  • 20
  • 41
  • 1) No, because it looks at the overloads of operator+ for pointers, you wont get implicit conversion on both operands. It wouldnt make much sense 2) [Cannot repro](http://coliru.stacked-crooked.com/a/a803931e63ae61ac) – Borgleader Aug 19 '15 at 15:14
  • `string s="hello!"` actually, this just uses the string constructor that takes `const char *`, no copy initialization is performed – yizzlez Aug 19 '15 at 15:14
  • 2
    @awesomeyi This isn't entirely correct either. First, a temporary `string` is constructed from the `"hello"` argument, and then moved (or copied in C++03) via direct-initialization to the `s` variable. – dyp Aug 19 '15 at 15:18
  • @awesomeyi I think that it does perform an implicit conversion. If I used the direct form of initialization like `string s("hello")`,that would call the ` const char*` constructor.When I use the copy form of initialization it needs the same class type so a conversion occurs ( if the constructor is marked explicit you can't use the copy form ). – Luca Aug 19 '15 at 15:20
  • 1
    @awesomeyi: (Appending to dyp's comment) ...unless the compiler does [copy elision](https://en.wikipedia.org/wiki/Copy_elision), in which case it does not actually create-and-copy the temporary, but does direct initialization. (§12.8 Copying class objects) This still requires an available copy constructor. – DevSolar Aug 19 '15 at 15:34
  • 2
    Although you didn't ask: to generate a single string literal from two others, you can rely on pre-processing to append them: `string s = "hello" " world";` Alternately, in C++14 and onward, you can use a std::string literal: `using namespace std::literals::string_literals; auto s = "hello"s + " world";`. – utnapistim Aug 19 '15 at 15:48
  • If you wonder what a compiler actually does when constructing a `std::string` here is [one of my answers to another question](http://stackoverflow.com/a/11639305/597607) showing that it can do `std::string s = "abcdefgh";`in 5 machine instructions. No temporaries and no copying. – Bo Persson Aug 19 '15 at 17:57

2 Answers2

2

1) Concatenating two string literals.

"Hello" + " world"

The compiler has no hint that it should be looking for anything related to std::string -- it is looking at two const char[] objects, and you cannot + those (or the const char * they could be degraded to).

2) Using operator+ on a char literal and a string literal.

(Thanks to User dyp for pointing in the right direction.)

If you literally mean a char literal -- e.g. 'a' -- then you're running afoul of one of the more surprising things C/C++ have to offer.

Consider: a[i] is equivalent to i[a]. (This is a fact.)

So, if you write:

'a' + "Hello"

...that is equivalent to (in ASCII)...

"Hello" + 97

...which is a pointer into nowhere, i.e. constructing a std::string from it is undefined behaviour.

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • yes, but you should be able to convert those const char* to two strings and then use the overloaded operator+(const string&,const string&) ? – Luca Aug 19 '15 at 15:26
  • @Luca: Please provide code. Plain English is not very precise to specify what, exactly, you're trying to do. – DevSolar Aug 19 '15 at 15:26
  • 1
    @Luca: You *can* do `std::string( "Hello" ) + " world"`, of course, because *then* the compiler *does* know to look for `std::string::operator+`. – DevSolar Aug 19 '15 at 15:36
  • @DevSolar ok, I now get the pointer thing, but what about the first question? I mean, why can the compiler figure out what overloaded operator to call when I concatenate a string and a string literal (like you say) but it can't guess when I use two string literals ( which are two const char arrays, or two pointers to a const char and can therefore be converted by the string constructor that takes a parameter of that type)? – Luca Aug 19 '15 at 15:38
  • @Luca: Why should it prefer turning those `const char *` into `std::string`, instead of, say, turning them into `int` and just adding those? One conversion is as likely as the other. That's why that kind of "I'll just convert everything" is not allowed. – DevSolar Aug 19 '15 at 15:40
  • becuase I provided a converting constructor from `const char*` to `string`. why should it choose to turn them into `int`s? – Luca Aug 19 '15 at 15:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/87397/discussion-between-devsolar-and-luca). – DevSolar Aug 19 '15 at 15:43
1

Borgleader already gave half the answer in comment:

  1. when adding two string litterals, compiler only sees two const char * and they could be cast to string but also to integers. So unless you explicitely say that you want them as strings, you get an error

  2. when adding a string litteral and a char, compiler sees a pointer and an integral number. It knows how to process that and does pointer arithmetics on your C string - which is probably not what you expected! There are chances that you end past the end of the char array and invoke undefined behaviour. Examples:

    "abc" + '0' => "abc" + 48 : 44 positions past the NULL ...
    "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij" + '0' => "ij"
    
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252