5

This may sound like a silly question, but I was confused about this following behaviour:

void funcTakingRef(unsigned int& arg) { std::cout << arg; }
void funcTakingByValue(unsigned int arg) { std::cout << arg; }

int main()
{
    int a = 7;
    funcTakingByValue(a); // Works
    funcTakingRef(a); // A reference of type "unsigned int &" (not const-qualified)
                      // cannot be initialized with a value of type "int"   
}

After thinking about it this kind of makes sense because in passing by value a new variable is created and conversion can be done, but not so much when passing the actual address of a variable, as in C++ once variables are made their type can't really change. I thought it's similar to this case:

int a;
unsigned int* ptr = &a; // A value of type int* cannot be used to 
                        // initialise an entity of type "unsigned int*"

But if I make ref function take a const the conversion works:

void funcTakingRef(const unsigned int& arg) { std::cout << arg; } // I can pass an int to this.

However not the same in the case of pointer:

const unsigned int* ptr = &a; // Doesn't work

I'm wondering what the reason for this is. I thought my reasoning was right that implicit conversion when passing by value made sense as a new variable is made, whereas because in C++ types never change once created you can't get an implicit conversion on a reference. But this doesn't seem to apply in a const reference parameter.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • Possible duplicate of [Can't pass temporary object as reference](https://stackoverflow.com/questions/27463785/cant-pass-temporary-object-as-reference) – xskxzr Feb 02 '18 at 05:27

2 Answers2

6

The point is the temporary.

References can't bind to variables with different type directly. For both cases int needs to be converted to unsigned int, which is a temporary (copied from int). The temporary unsigned int could be bound to lvalue-reference to const (i.e. const unsigned int&), (and its lifetime is extended to the lifetime of the reference,) but can't be bound to lvalue-reference to non-const (i.e. unsigned int&). e.g.

int a = 7;
const unsigned int& r1 = a; // fine; r1 binds to the temporary unsigned int created
// unsigned int& r2 = a;    // not allowed, r2 can't bind to the temporary
// r2 = 10;                 // trying to modify the temporary which has nothing to do with a; doesn't make sense
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
5

const & allows the compiler to generate a temporary variable, which gets thrown away after the call (and the function can’t change it, as it is const).
For non-const, the function would be able to modify it, and the compiler would have to transfer it back to the type it came from, which would lead to all kinds of issues, so it’s not allowed/possible.

Aganju
  • 6,295
  • 1
  • 12
  • 23