Implicit conversion : const reference vs non-const reference vs non-reference

天大地大妈咪最大 提交于 2019-11-30 13:28:15

问题


Consider this code,

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

This compiles fine, runs fine. But if I change f(B) to f(B&), it doesn't compile. If I write f(const B&), it again compiles fine, runs fine. Why is the reason and rationale?

Summary:

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

I would like to hear reasons, rationale and reference(s) from the language specification, for each of these cases. Of course, the function signatures themselves are not incorrect. Rather A implicitly converts into B and const B&, but not into B&, and that causes the compilation error.


回答1:


I would like to hear reasons, rationale and reference(s) from the language specification

Is The Design and Evolution of C++ sufficient?

I made one serious mistake, though, by allowing a non-const reference to be initialized by a non-lvalue [comment by me: that wording is imprecise!]. For example:

void incr(int& rr) { ++rr; }

void g()
{
    double ss = 1;
    incr(ss);    // note: double passed, int expected
                 // (fixed: error in release 2.0)
}

Because of the difference in type the int& cannot refer to the double passed so a temporary was generated to hold an int initialized by ss's value. Thus, incr() modified the temporary, and the result wasn't reflected back to the calling function [emphasis mine].

Think about it: The whole point of call-by-reference is that the client passes things that are changed by the function, and after the function returns, the client must be able to observe the changes.




回答2:


The problem is that the implicit conversion from a to a B object yields an rvalue. Non-const references can only bind to lvalues.

If B had a default constructor you would get the same behavior if you change the f(a) call to f(B()).

--

litb provides a great answer to what is an lvalue: 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?

--

To explain with references to the standard how those function calls fail or succeed would be excessively long. The important thing is how B& b = a; fails while const B& b = a; does not fail.

(from draft n1905)

A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:
- [is an lvalue and is either reference compatible or implicitly convertible to an lvalue of a reference compatible type...]
- Otherwise, the reference shall be to a non-volatile const type (i.e., cv1 shall be const).

Here's a case where something is convertible to an lvalue of reference compatible type.



来源:https://stackoverflow.com/questions/4704404/implicit-conversion-const-reference-vs-non-const-reference-vs-non-reference

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!