按姓名呼叫(正常订单评估)

时间:2014-04-17 11:05:38

标签: c++ parameter-passing pass-by-name

我在下面有以下代码(C like language)。我知道如何使用pass-by-value或pass-by-reference来跟踪,但是还有call-by-name机制。任何人都可以指导我如何跟踪呼叫名称吗?

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

如果使用pass-by-value,输出将如下所示:

4 12 4 11

4 11 4

12 5 12 13

12 13 4

1 个答案:

答案 0 :(得分:2)

通常,C ++ 使用call-by-name。 Call-by-name表示函数调用时不计算函数的参数。它的行为就好像参数将被替换为函数体。

示例:

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一次,并将结果赋予函数foo

使用call-by-name的语言可能会将foo(3,bar(7));转换为

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

在第一种情况下,函数bar将被评估一次,在第二种情况下,它将被评估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;,因此永远不会调用函数bar。我认为这种优化只有在确保bar没有副作用时才会完成。


虽然C ++不使用call-by-name,但您可以轻松地在C ++中使用ideom。只需给出函数的函数对象/指针。

示例:

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++; }),其中第二个参数是C ++ 11 lambda,每次在代码中遇到b时都会计算b。