void swap(int& a, int& b) {}
void copy(int& a, const int& b) {}
int main() {
int a=1;
unsigned b=2;
swap(a, b);
copy(a, b);
}
C++ language, the g++ compiler.
Please tell me why there won't be a compilation error in a copy-function call, but in a swap-function triggers invalid initialization of reference of type ‘int&’ from expression of type ‘unsigned int’
.
Sorry for my bad English.
First of all - the rules L for reference binding of an expression of type U
with qualification cv2
to a reference of type T
with qualification cv1
.:
A reference to
cv1 T
can be initialized by an expression of typecv2 U
if the reference is an lvalue reference and the initializer expression
- is an lvalue and
cv1 T
is reference-compatible withcv2 U
, or- has a class type [ ... ].
Otherwise,
cv1
shall beconst
or the reference shall be an rvalue reference.
cv1 T
is reference-compatible tocv2 U
ifT
is the same types asU
(or a base ofU
) and ifcv1
is equal tocv2
(or greater).
Unfortunatelly (or luckily?! ;)) a function with a non-constant lvalue reference parameter cannot be called with an lvalue of a non-reference-compatible type (or in case of class types without a viable conversion of the passed argument to a reference-compatible type).
Let's consider a function that takes an integer reference and a second one that has a constant integer reference paramter.
void doSomething (int & x)
{
// do some READ & WRITE stuff with x
x = x+5;
}
int doSomethingElse (int const & x)
{
// do some READ ONLY stuffwith x
return 3*x;
}
Let's look at a single signed and another unsigned value:
int a = 1;
unsigned int b = 2;
Now we pass the int
named a
to doSomething()
:
// works since x of doSomething can bind to a
doSomething(a);
// let's try to expand/"inline" what is happening
{
int & x = a;
x = 5;
}
No magic here, reference x
binds to a
and is set to 5 (and therefore a, too). Fine.
Now we try to pass b
to the same function. But ...
// ... it doesn't work/compile since
// unsigned int is not reference compatible to int
doSomething(b); // compile error here
// what's going on here
{
int & x = b; // unsigned value cannot bind to a non-const lvalue reference!
// compile error here
x = 5;
}
Here we start having trouble and calling doSomething
with b
will not compile.
Let's look at the const reference function now. Passing a
is obviously not problematic again. A const int reference is bound to an int
value.
int c = doSomethingElse(a);
// let's do some naive inlining again
int c;
{
int const & x = a;
c = 3*x;
}
Well seems alright. c
will be 3*a
.
Now what happens if we pass b
to that function? The standard says that, in this case, a temporary of type cv1 T
is created and initialized from the initializer expression using copy initialization rules.
int d = doSomethingElse(b);
// expanding this to:
int d;
{
int temp = b; // implicit conversion, not really an lvalue!
int const & x = temp;
d = 3*x;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With