8

次の関数のチェーンは、C ++標準(C ++ 0xを想定)に従って不特定のシーケンスになると思います。確認が必要な場合は、誰かが説明を提供していただければ幸いです。

#include <iostream>

struct TFoo 
{
    TFoo(int) 
    {
        std::cout<<"TFoo"<<std::endl;
    };
    TFoo foobar1(int) 
    {
        std::cout<<"foobar1"<<std::endl;
        return *this;
    };
    TFoo foobar2(int) 
    {
        std::cout<<"foobar2"<<std::endl;
        return *this;
    };
    static int bar1() 
    {
        std::cout<<"bar1"<<std::endl;
        return 0;
    };
    static int bar2() 
    {
        std::cout<<"bar2"<<std::endl;
        return 0;
    };
    static int bar3()
    {
        std::cout<<"bar3"<<std::endl;
        return 0;
    }
};

int main(int argc, char *argv[])
{
    // is the sequence well defined for bar1, bar2 and bar3?
    TFoo(TFoo::bar1()).foobar1(TFoo::bar2()).foobar2(TFoo::bar3());
}

*編集:関数の__fastcall指定子を削除しました(必須ではありません/質問に関連します)。

4

2 に答える 2

8

評価順序は指定されていません。ドラフトC++0x仕様の関連セクションは、 1.9、パラグラフ14および15です。

14完全式に関連するすべての値の計算と副作用は、評価される次の完全な式に関連するすべての値の計算と副作用の前に順序付けられます。

15特に明記されていない限り、個々の演算子のオペランドおよび個々の式の部分式の評価は順序付けられていません。

ここで、関連する完全な式は次のとおりです。

TFoo(TFoo::bar1()).foobar1(TFoo::bar2()).foobar2(TFoo::bar3());

そのため、その部分式の評価は順序付けられていません(どこかで見逃した例外がない限り)。

以前の標準には、同じ効果を持つ言語が含まれていると確信していますが、「シーケンスポイント」の観点からです。

[編集]

パラグラフ15はまた言う:

関数を呼び出すとき(関数がインラインであるかどうかに関係なく)、引数式、または呼び出された関数を指定する後置式に関連するすべての値の計算と副作用は、本体のすべての式またはステートメントの実行前にシーケンスされます。関数と呼ばれます。[注:異なる引数式に関連する値の計算と副作用は順序付けられていません。—エンドノート]

「呼び出された関数を指定する接尾辞式」は、inのようなものfoo().barですfoo().bar()

ここでの「注」は、引数の評価順序が「未指定の順序」のデフォルトの例外ではないことを明確にするだけです。推論によれば、どちらも「呼び出された関数を指定する接尾辞式」に関連付けられた評価順序ではありません。thisまたは、必要に応じて、引数の式の評価順序。(例外があった場合は、これを指定するのが自然な場所です。または、関数呼び出しについて説明しているセクション5.2.2もあります。どちらのセクションも、この例の評価順序については何も述べていないため、指定されていません。)

于 2011-07-14T01:24:42.530 に答える
1

はい、関数の引数の評価の順序は指定されていません。

私の場合、Linux上のgcc4.5.2は

bar3
bar2
bar1
TFoo
foobar1
foobar2

しかし、Linuxではclang ++、solarisではgcc3.4.6が生成されます

bar1
TFoo
bar2
foobar1
bar3
foobar2

より簡単な例を分析するために、は2つの引数を取るTFoo(0).foobar1(TFoo::bar2());呼び出しです。部分式の結果(非表示の引数として)と部分式の結果です。私の場合、gccは最初に実行し、次にTFooのコンストラクターを実行し、次にを呼び出します。たとえば、clang ++は、最初にTFooのコンストラクターを実行し、次にを呼び出します。TFoo::foobar1TFoo(0)thisTfoo::bar2()bar2()foobar1()bar2()foobar1()

于 2011-07-14T01:23:57.490 に答える