11

考虑这段代码,

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

编译得很好,运行良好。但是,如果我更改f(B)f(B&),它不会编译。如果我写f(const B&),它再次编译良好,运行良好。原因和道理是什么?

概括:

void f(B);         //okay
void f(B&);        //error
void f(const B&);  //okay

我想听听语言规范中每种情况的原因、理由和参考资料。当然,函数签名本身并没有错。而是A隐式转换为Band const B&,但不转换为B&, 并导致编译错误。

4

2 回答 2

9

我想听听语言规范中的原因、理由和参考资料

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由 's 初始化ss的值。因此,incr()修改了临时的,结果并没有反映回调用函数[强调我的]。

想一想:call-by-reference 的全部意义在于,客户端传递了被函数改变的东西,而函数返回后,客户端必须能够观察到这些变化

于 2011-01-16T09:20:49.877 回答
4

问题是从 a 到 B 对象的隐式转换会产生一个右值。非常量引用只能绑定到左值。

如果 B 有一个默认构造函数,如果将f(a)调用更改为f(B()).

--

litb 为什么是左值提供了一个很好的答案:堆栈溢出 - 经常使用的很少定义的术语:左值

GotW #88:“最重要的 const”的候选人</a>

Stack Overflow - 为什么非常量引用不能绑定到临时对象?

--

参考标准来解释这些函数调用如何失败或成功将过长。重要的是如何B& b = a;失败而const B& b = a;没有失败。

(来自草案 n1905)

对“cv1 T1”类型的引用由 cv2 T2”类型的表达式初始化 ,如下所示
:引用应为非易失性 const 类型(即 cv1 应为 const)。

这是一个可以转换为引用兼容类型的左值的情况。

于 2011-01-16T08:32:27.447 回答