0

以下のコードがあります(Cのような言語)。値渡しまたは参照渡しが使用されたかどうかを追跡する方法は知っていますが、名前による呼び出しメカニズムもあります。名前による呼び出しを追跡する方法を教えてもらえますか?

int x=12,y=10;
void tswap(int pa, int pb) {
   int tmp;
   tmp=pa;
   pa=pb;
   pb=tmp;
   x=x+pa;
   x=x-pb;
   y++;
   printf("%d %d %d %d\n",pa,pb,x,y);
}
int main() {
    int a=4;
    tswap(x,a);
    printf("%d %d %d\n",x,y,a);
    tswap(++x,++y);
    printf("%d %d %d\n",x,y,a);
    return 0;
}

値渡しが使用される場合、出力は次のようになります。

4 12 4 11

4 11 4

12 5 12 13

12 13 4

4

1 に答える 1

2

一般に、C++ は名前による呼び出しを使用しません。名前による呼び出しとは、関数への引数が関数呼び出しで評価されないことを意味します。引数が関数本体に代入されたかのように動作します。

例:

void foo(int a, int b) {
    int s = 0;
    for(int i=0; i<n; i++) {
        s += b;
    }
}

通常、C++ では、式の例は次のようx = foo(3,bar(7));に動作します。

int tmp = bar(7);
x = foo(3,tmp);

barは 1 回評価され、その結果が関数に渡されますfoo

名前による呼び出しを使用する言語は、潜在的に次のように変換foo(3,bar(7));されます。

void foo() {
    int s = 0;
    for(int i=0; i<3; i++) {
        s += bar(7);
    }
}

最初のケースでは関数barは 1 回評価され、2 番目のケースでは複数回評価され3ます。


ただし、その規則には例外があります。関数宣言が既知の場合 (テンプレートやインラインなど)、オプティマイザはそれを使用して最適化されたコードを生成できます。

例:

inline unsigned foo(unsigned a, unsigned b) {
    return a / b;
}

a = foo(x,2);コンパイラを呼び出すa = x/2;と、それをに変換してから に変換するのに十分なほどスマートになりa = x >> 1;ます。

これは、次の例にも当てはまります。

inline int foo(int a, int b) {
    if(a == 0) return 0;
    else return b;
}

これで、コンパイラは実際に関数を呼び出さないように変換x = foo(0,bar(17));できx = 0;ますbarbarこの最適化は、副作用がないことが保証されている場合にのみ行われると思います。


C++ は名前による呼び出しを使用しませんが、C++ ではイデオムを簡単に使用できます。関数に関数オブジェクト/ポインターを与えるだけです。

例:

template<typename F>
int foo(int a, F b) {
    int s = 0;
    for(int i=0; i<a; i++) {
        s += b();
    }
}

foo(3, []() { static int i=0; return i++; })2 番目の引数が C++11 ラムダである では、コード内で b が検出されるたびに評価されます。

于 2014-04-17T12:54:45.317 に答える