The context of my question is the implementation of a simplistic stack-based virtual machine. My implementation of the addition and multiplication operations looks like this:
case OP_ADD: Push(Pop() + Pop()); break;
case OP_MUL: Push(Pop() * Pop()); break;
Since addition and multiplication are commutative operations, it doesn't matter which order the Pop calls are evaluated as long as the side effects (i.e., updating the virtual machine's stack pointer) of the first Pop call (whichever one that is) will be completed before the other Pop call.
With subtraction and division, the order does matter, so we have to ensure we control which Pop is executed first. For example, here's the implementation of the subtraction operation:
case OP_SUB: {
const auto subtrahend = Pop();
const auto minuend = Pop();
Push(minuend - subtrahend);
break;
}
I've heard vague claims that C++17 has tightened up the sequence-point and sequencing rules, but I've not heard details. I'm no longer enough of a language lawyer to parse the spec confidently in this regard.
Do the changes in C++17 provide enough sequencing guarantees that subtraction could be implemented as a single expression as with addition and multiplication? Are the order of the Pop() calls and their side effects defined, implementation-defined, or unspecified?