考虑这段代码,
struct A {};
struct B { B(const A&) {} };
void f(B)
{
cout << "f()"<<endl;
}
void g(A &a)
{
cout << "g()" <<endl;
f(a); //a is implicitly converted into B.
}
int main()
{
A a;
g(a);
}
这个compiles fine,运行正常。但是,如果我将f(B)
更改为f(B&)
,则doesn't compile。如果我写f(const B&)
,它再次compiles fine,运行正常。原因和理由是什么?
要点:
void f(B); //okay
void f(B&); //error
void f(const B&); //okay
我希望听到语言规范中的原因,基本原理和参考资料。当然,功能签名本身并不正确。相反,A
隐式转换为B
和const B&
,但不转换为B&
,这会导致编译错误。
答案 0 :(得分:7)
我想听听语言规范中的原因,理由和参考资料
C ++的设计和演变是否足够?
但是,我犯了一个严重的错误,允许非const引用由非左值初始化[由我发表评论:措辞不精确!]。例如:void incr(int& rr) { ++rr; } void g() { double ss = 1; incr(ss); // note: double passed, int expected // (fixed: error in release 2.0) }
由于类型不同,
int&
无法引用传递的double
,因此会生成一个临时值来保存int
初始化ss
的值。因此,incr()
修改了临时,结果未反映回调用函数 [强调我的]。
考虑一下:引用调用的全部内容是客户端传递函数更改的内容,在函数返回后,客户端必须能够观察到更改
答案 1 :(得分:4)
问题是从a到B对象的隐式转换产生rvalue。非const引用只能绑定到左值。
如果B有默认构造函数,如果将f(a)
调用更改为f(B())
,则会产生相同的行为。
-
litb为左值提供了一个很好的答案:Stack Overflow - often used seldom defined terms: lvalue
GotW #88: A Candidate For the “Most Important const”
Stack Overflow - How come a non-const reference cannot bind to a temporary object?
-
通过引用标准来解释这些函数调用失败或成功的时间过长。重要的是B& b = a;
失败,而const B& b = a;
没有失败。
(来自草案n1905)
类型“cv1 T1”的引用由类型“cv2 T2”的表达式初始化,如下所示:
- [是左值并且参考兼容或可隐式转换为参考兼容类型的左值... ]
- 否则,引用应为非易失性const类型(即,cv1应为const)。
Here's可以将某些内容转换为参考兼容类型左值的情况。