3

I am curious why there is a difference in the argument evaluation order between chained static functions and member functions. From the answers at this question I can see it is unspecified what the argument evaluation order is between such chained function calls. Take for example the following snippet:

#include <iostream>
class test {
public:
    static test& chain_s(test& t, int i) {
        std::cout << i << " ";
        return t;
    }

    test& chain(test& t, int i) {
        std::cout << i << " ";
        return *this;
    }
};

int main(int, char**) {
    int x = 2;
    test t;
    t.chain(t,++x).chain(t,++x).chain(t,++x);
    x = 2; std::cout << std::endl;
    t.chain_s(t,++x).chain_s(t,++x).chain_s(t,++x);

    return 0;
}

In the case of GCC 4.6.2 and CL 15.00.30729.01 (MSVC 9) the resulting output is for me

5 5 5
3 4 5

However, I was wondering if there is any reason in the specification or if it is otherwise known why the static function are evaluated left-to-right (with their arguments), and for the non-static function all the arguments first (right-to-left from what I've seen in other tests).

The reason I'm asking this is because I first noticed this difference in behavior when trying to get similar behavior in C (using a struct and a function pointer) and failed. I strongly suspect this is some optimization implemented both in GCC and MSVC for member functions, but I hope someone here can shed a little more light on this.

Edit:
I forgot to mention one crucial bit of information which strikes me as odd: GCC will only warn on unspecified behavior on the chained non-static function, but not the static functions:

a.cpp: In function 'int main(int, char**)':
a.cpp:18:45: warning: operation on 'x' may be undefined [-Wsequence-point]

GCC is not obligated to provide such warnings so it could miss the second expression, but this is what leads me to believe something interesting is going on.

Community
  • 1
  • 1
harrbharry
  • 71
  • 2

2 Answers2

2

No reason. Like you say, the order is unspecified by the language.

One reason for using right to left order is that functions with a variable number of parameters, like printf, will then always have the first parameter on top. Otherwise it doesn't matter.

Bo Persson
  • 86,087
  • 31
  • 138
  • 198
  • I forgot to ask why the compiler output messages differ, any ideas on that? This is also what led to this entire question. – harrbharry Jan 17 '12 at 19:50
  • Even with `printf`, the compiler can evaluate the arguments in any order it pleases, or even interleave the evaluations. On a stack based machine, the first argument is likely to be the last pushed, but there's also a good chance that the compiler just reserves the necessary space on the stack, and stores each argument where it belongs using sp-relative addressing. And doing so in whatever order it finds convenient. – James Kanze Jan 17 '12 at 20:09
2

Your code has undefined behavior, but I suppose you know that. Also, you could easily see a difference depending on optimization flags. But in this case, one likely reason is that the non-static functions require three arguments, including the results of the previous call, where as the static functions only require two, and the results of the previous call are ignored.

James Kanze
  • 142,482
  • 15
  • 169
  • 310