Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why std::string concatenation operator works like right-associative one?

Running the following MWE extracted from my pet project and compiled with GCC 4.9.1 (and 4.8.1 also)

#include <iostream>
#include <string>
#include <sstream>

class InputStringStream
{
public:
    InputStringStream(const std::string& str) : istringstream(str), currentLine() {}
    std::string readLine()
    {
        std::getline(istringstream, currentLine);
        return currentLine;
    }

private:
    std::istringstream istringstream;
    std::string currentLine;
};

int main()
{
    std::string s = std::string("line1\nline2\nline3");
    InputStringStream stream(s);
    std::cout << stream.readLine() + "\n" + stream.readLine() + "\n" + stream.readLine() << std::endl;
    return 0;
}

produces the following output

line3
line2
line1

while I expect

line1
line2
line3

What I'm doing wrong?

P.S. The same code compiled with Apple LLVM compiler version 5.1 produces what I expect. Visual C++ 2012 is on GCC side.

like image 485
Wildcat Avatar asked Sep 15 '14 07:09

Wildcat


People also ask

Which operator can be used in string concatenation?

The & operator is recommended for string concatenation because it is defined exclusively for strings and reduces your chances of generating an unintended conversion.

How to concatenate characters into a string in c++?

C++ has a built-in method to concatenate strings. The strcat() method is used to concatenate strings in C++. The strcat() function takes char array as input and then concatenates the input values passed to the function.

Which operator is also known as concatenation operator?

The concatenation operator is a binary operator, whose syntax is shown in the general diagram for an SQL Expression. You can use the concatenation operator ( || ) to concatenate two expressions that evaluate to character data types or to numeric data types.


2 Answers

The order of evaluation of function arguments is unspecified, so what you're doing wrong is holding mistaken, unwarranted beliefs and expectations. (Overloaded operators like + and << are just ordinary function calls.)

You have to extract the stream elements in a deterministic order, and it's your responsibility to do so. For example:

std::cout << stream.readLine() + '\n';
std::cout << stream.readLine() + '\n';
std::cout << stream.readLine() + '\n';

Even better, avoiding redundancy and temporary strings:

for (auto i : { 1, 2, 3 }) { std::cout << stream.readLine() << '\n'; }
like image 81
Kerrek SB Avatar answered Nov 24 '22 00:11

Kerrek SB


The problem is not about associativity, in this expression:

stream.readLine() + "\n" + stream.readLine() + "\n" + stream.readLine() 

It's unspecified which stream.readLine() is called first.

like image 33
Yu Hao Avatar answered Nov 23 '22 23:11

Yu Hao