0

I was reading this book and it is written that We can assign const reference of one type to an object of any other type, and the reason was given that, internally compiler assign the Rvalue to the object of the same type as reference and then const reference is initialized to that object of same type, But, if this type of implicit conversion is helping in getting const reference assigned to different type of objects, then why it is not possible to do that same conversion implicitly, because for this explicit conversion.

#include<iostream>
using namespace std;
int main()
{
    int a = 10;

    double temp = (double)a;
    double &x = temp;
    cout << x << endl;
    return 0;
}

It is working the same way, why it is not pre-configured in the compiler?

dukeforever
  • 298
  • 1
  • 7
  • 2
    This question is really hard to follow. What behaviour are you asking about? The types match in your example, but your phrasing implies that they shouldn't. Do you mean like `double &x = a`? – tadman Aug 18 '20 at 21:55
  • *We can assign const reference of one type to an object of any other type, and the reason was given that, internally compiler assign the Rvalue to the object of the same type as reference and then const reference is initialized to that object of same type* Without code samples that sentence is hard to understand. – R Sahu Aug 18 '20 at 21:57
  • Because you can't assign an rvalue to a non-const reference? In your example, `temp` is an lvalue, so it is not the same – Artyer Aug 18 '20 at 21:57
  • It sounds like you think `x` is a reference to `a`. This is not the case. It is a reference to `temp` which is a `double` and `temp` was initialized to the value `a` had, which is `10`. – François Andrieux Aug 18 '20 at 21:59
  • If you have a code sequence (that would compile; this doesn't) `int a = 10; double &x = a; x = 7; cout << a;` what value would you expect to be printed? – 1201ProgramAlarm Aug 18 '20 at 22:00
  • 1201ProgramAlarm, according to book that will be an error. – dukeforever Aug 18 '20 at 22:03
  • I saw the vagueness in my comment after I submitted it, so I edited to clarify that it wouldn't compile. If I read your question right, you asking why code like that doesn't compile? – 1201ProgramAlarm Aug 18 '20 at 22:04
  • I was asking that, even it does matter that we use const or not, because we are not still referencing to the original object in both cases, which we want to reference on. – dukeforever Aug 18 '20 at 22:08
  • @dukeforever You can't create a reference of an unrelated type and have it refer to the original type. It just doesn't work that way. In your example, you can't have a non-const `double&` reference to an `int` variable, only to a (non-temporary) `double` variable. But you *can* have a `const double&` reference to a (temporary) `double` that is initialized from the value of that `int`. – Remy Lebeau Aug 18 '20 at 22:10

2 Answers2

6

If the compiler has to perform an implicit conversion from one type to another, that means it has to create a temporary to hold the converted value.

A non-const reference cannot bind to a temporary. Period.

A const reference can, and it will extend the lifetime of the temporary.

In other words:

#include <iostream>
using namespace std;

int main()
{
    int a = 10;

    double &x = (double)a; // ERROR! Can't bind to the temporary double
    cout << x << endl;

    const double &x2 = (double)a; // OK! Binds to the temporary double
    cout << x2 << endl;

    return 0;
}

Live Demo

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

In brief, it's to help you avoid mistakes. Suppose for the moment that you could assign an object to a non-const reference of another type, as in:

// DISCLAIMER: bad code; does not compile
int a = 10;
double &x = a;
x = 2.0;

What would this mean? The second line would mean that x is an alias for a, implying that changes to x are reflected in a. If you did not intend this implication, then a non-const reference is not the right tool. (If there will be no changes to x, use a const reference. If changes are not supposed to be reflected in a, use a copy instead of a reference.) So the third line should set the value of a to 2. However it cannot.

  1. Implicit conversions are easily one-way. There might not be a reverse conversion. Sure, in this specific example, converting the floating point 2.0 to the integer 2 is not problematic, but this is a special case. When you look at more complicated scenarios, especially scenarios involving classes instead of fundamental types, the reverse conversion might not even makes sense. Modifying via the reference is not something the language can guarantee, so it is prohibited in all cases for consistency.

  2. The implicit conversion involves making a temporary object. If you compile the line const double &x = a; the compiler would do the same thing your code does: create a new float object and have x refer to this new object. In the compiler's version the float object has no name, while in your code, it is called temp. In your code, if you were to try to modify x, the modifications would appear in temp, but not in a because they are different objects. The same with the compiler's version – if you were able to modify through the reference, you would be modifying the temporary, not the original object. This breaks the semantics of references.

The upshot is that if you think you need a non-const reference to an object of a different type (one that requires a conversion), there is likely a problem with your logic. The compiler can identify this quickly and tell you that you are trying something that will not work the way you probably think it will. This is a pitfall with no known utility, so big orange cones are here to ward off the unwary. Don't waste time testing your executable, because a bug has already been identified.

The language rules allow the compiler to be helpful by pointing out this near-certain error at compile-time, saving you the trouble of debugging run-time symptoms.

JaMiT
  • 14,422
  • 4
  • 15
  • 31