This is intended to add information on the matter. with regards to C++17 paper. The proposal (Refining Expression Evaluation Order for Idiomatic C++ (RevisionRevision 2)) for C++17 addressed the issue above. Theciting the code above was specifically used as a specimen for.
As suggested, I added relevant information from the proposal and to quote (highlights mine):
The order of expression evaluation, as it is currently specified in the standard, undermines advices, popular programming idioms, or the relative safety of standard library facilities. The traps aren't just for novices or the careless programmer. They affect all of us indiscriminately, even when we know the rules.
Consider the following program fragment:
void f() { std::string s = "but I have heard it works even if you don't believe in it" s.replace(0, 4, "").replace(s.find("even"), 4, "only") .replace(s.find(" don't"), 6, ""); assert(s == "I have heard it works only if you believe in it"); }The assertion is supposed to validate the programmer's intended result. It uses "chaining" of member function calls, a common standard practice. This code has been reviewed by C++ experts world-wide, and published (The C++ Programming Language, 4th edition.) Yet, its vulnerability to unspecified order of evaluation has been discovered only recently by a tool.
The paper suggested changing the pre-C++17 rule on the order of expression evaluation which was influenced by C and have existed for more than three decades. It proposed changesthat the language should guarantee contemporary idioms or risk "traps and sources of obscure, hard to find bugs" such as what happened with the code specimen above.
The proposal for C++17 is to require that every expression has a well-defined evaluation order:
- Postfix expressions are evaluated from left to right. This includes functions calls and member selection expressions.
- Assignment expressions are evaluated from right to left. This includes compound assignments.
- Operands to shift operators are evaluated from left to right.
- The order of evaluation of an expression involving an overloaded operator is determined by the order associated with the corresponding built-in operator, not the rules for function calls.
The above code compiles successfully using GCC 7.1.1 and Clang 4.0.0.