我在下面有以下代码(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
答案 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。