2012-01-17 24 views
3

なぜ連鎖静的関数とメンバ関数の間に引数の評価順序に違いがあるのか​​不思議です。 this questionの回答から、そのような連鎖関数呼び出しの間で引数の評価順序が何であるかは不明です。しかし、私は思っていた場合GCC 4.6.2及びCL 15.00.30729.01(MSVC 9)の場合に得られる出力は私連鎖静的関数呼び出し間の引数評価順序

5 5 5 
3 4 5 

するためのものである

#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; 
} 

:例えば、次のコードを取ります仕様に何らかの理由がある、あるいは静的関数が左から右へ(引数で)評価され、非静的関数からすべての引数が最初から(右から左へ他のテストで見たように)。

これは、構造体と関数ポインタを使用してCで同様の動作をさせようとしたときに、この動作の違いが最初に気付き、失敗したためです。私はこれがGCCとMSVCの両方でメンバー関数のために実装されたいくつかの最適化だと強く思っていますが、ここで誰かがこれについてもう少し詳しく説明してくれることを願っています。

編集:
Iが奇数として私を打つ情報の一つの重要なビットを言及するのを忘れてしまった:GCCは静的関数の連鎖非静的関数に指定されていない行動に警告ではなくなります。

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

GCCは、2番目の表現を見逃す可能性があるような警告を出す義務はありませんが、これは興味深いことが起こっていると私に導きます。

+0

あなたが書いたコードでこのようなことは無関係でなければなりません。 –

+0

はい、私はいくつかのコードに誤りがありますが、同様の場合には警告を出さない理由を知りたいと思います。 – harrbharry

答えて

2

理由はありません。あなたが言うように、命令は言語によって不特定である。

右から左の順序を使用する理由の1つは、printfのような可変数のパラメータを持つ関数は、最初に常に先頭のパラメータを持つことです。さもなければそれは重要ではない。

+0

私はなぜコンパイラの出力メッセージが異なるのか尋ねることを忘れて、それについてのアイデア?これはまた、この全体の問題につながったものです。 – harrbharry

+0

'printf'であっても、コンパイラは任意の順序で引数を評価したり、評価をインターリーブすることさえできます。スタックベースのマシンでは、最初の引数が最後にプッシュされる可能性がありますが、コンパイラがスタックに必要な領域を予約し、sp相対アドレス指定を使用して各引数を格納している可能性があります。それを好きな順番に並べると便利です。 –

2

あなたのコードには未定義の動作がありますが、あなたはそれを知っていると思います。また、 では、最適化フラグによって違いを簡単に見ることができます。しかし、 の場合、1つの理由は、非静的関数が の前の呼び出しの結果を含む3つの引数を必要とするということです。この場合、静的関数は2つしか必要なく、前の 呼び出しの結果は無視されます。

関連する問題