Search code examples
c++stringgccvisual-c++-2012

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.


Solution

  • 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'; }