为什么这些定义都可以:
int func(int p=255) {
return p;
}
int func1(const int &p=255) {
return p;
}
但是这个定义:
int func2(int &p=255) {
return p;
}
导致编译错误?
它背后的逻辑是什么?
答案 0 :(得分:3)
通过引用方式获取参数,您不使用变量的本地副本,但使用已在调用函数范围内定义的变量。
虽然你的第一个例子是有意义的(你有一个可以填充默认值的局部变量p),但第二个例子有点棘手:通常在使用引用时你希望变量有一个地址,因为你想要修改它。对于const-refernces,编译器仍然允许你传递一个文字,即使像“引用文字”这样的东西根本没有意义。
在第三种情况下,编译器希望您修改p。但这种修改应该影响哪一部分记忆? “255”没有地址 - 因此它不能用作参考。
如果您想要更详细的解释,您应该寻找“rvalue”和“lvalue”等关键字。
答案 1 :(得分:2)
非const引用必须绑定到左值(即可以获取其地址)。 255
(即int literal)不是左值,因此int &p=255
失败。
const引用可以绑定到rvalue,对于这种情况,将创建一个临时int
并从255
初始化。临时int
的生命周期与const引用相同。
答案 2 :(得分:0)
尝试的功能定义
auto func2( int& p = 255 )
-> int
{ return p; }
...失败,因为您无法将rvalue绑定到对非const
的引用。基本上,该规则是因为像255
这样的简单值不可修改。虽然引用可用于修改。
一个简单的解决方案是将默认值表示为单独的重载:
auto func2( int& p )
-> int
{ return p; }
auto func2()
-> int
{
int scratchpad = 255;
return func2( scratchpad );
}
答案 3 :(得分:0)
int func(int p=255) {
return p;
}
p
此处按值复制,并且定义为存在于func
的范围内。
int func2(int &p) {
return p;
}
// e.g. use:
int value = 10;
func2(value); // func2 *could* modify value because it is passed by non-const reference
在这种情况下,编译器在此期望p
在内存中的某个位置(即左值),因此它可以在func2
内写入它。通过非const引用传递允许您修改函数调用中使用的变量。由于p
必须属于其他人,因为它可以修改,因此您无法为其指定默认值。
但是const参考案例怎么样?在这里,编译器足够聪明,知道p
永远不会被写入,因为它是const,因此它不需要在内存中有一个名称来写入。在传递文字的情况下(例如255),它(在幕后)基本上创建一个临时变量并将该临时变量传递给函数。
int func1(const int &p=255) {
return p;
}
func1(10);
// Behind the scenes, the compiler creates something along these lines
// since it can never be modified.
const int some_temporary = 10;
func1(some_temporary);