Cannot convert 'a' (type 'int') to type 'double &
I am following some C ++ tutorials and unfortunately the source material states that this particular function call cannot be made, but by no means explains why:
template<typename T>
void Swap(T &a, T &b){
T temp;
temp = a;
a = b;
b = temp;
}
So now I create an explicit template instantiation and pass in a
and b
;
int a = 5;
double b = 10.3;
Swap<double>(a, b);
Which then throws the following compiler error:
cannot convert 'a' (type 'int') to type 'double &'
My only guess is that this is due to a rule that states that r cannot be bound to a non-const reference, however, if it T &a
is just an alias, it is not the rvalue itself, is it? My implicit cast creates a temporary one that it can't bind to T &a
? Is this what's going on?
temp
- value l. It can only have a scope, but it does exist. So why not let it implicitly double-click and then assign a reference to a temp
? The intent looks pretty clear. I don't quite understand links as parameters. If a
temp is assigned, which is an lvalue, then isn't that allowed?
This means that I am even on the right track here.
Edit:
Second example:
int a = 5;
double &d = a; // invalid initialization of reference of type 'double&' from expression of type 'int'
However
int a = 5;
const double &d = a; //valid
source to share
Intuitively, swapping a
and b
must work, because the compiler can convert between int
and double
. In practice, however, think about what the compiler has to do to do what you ask.
You start with a template:
template<typename T>
void Swap(T &a, T &b){
T temp = a;
a = b;
b = temp;
}
To instantiate for double
, the compiler creates a function like this:
void Swap(double& a, double& b) {
double temp = a;
a = b;
b = temp;
}
These are reference parameters - they point to actual locations in memory, not aliases or copies. Under the hood, a link behaves like a pointer, so you can think of your function in a similar way if it helps:
void Swap(double* a, double *b);
In other words, it Swap
needs references (pointers) to two doubles in memory - two 8-byte sections of memory (assuming a double is 8 bytes). As intelligent and intuitive people, we know that an implementation Swap
doesn't really need two 8-byte sections of memory, but how it is declared and how the compiler applies it.
To create a version of Swap that can handle mixed arguments, you need to do something like this:
template<typename T1, typename T2>
void Swap(T1& a, T2& b) {
T1 tmp(a);
a = b;
b = tmp;
}
source to share
What you are trying to do is effective:
int a = 5;
double& dr = a;
The rules governing the initialization of references in the standard are given in section 8.5. First, some definitions:
(4) For types "cv1
T1
" and "cv2T2
", "cv1T1
" refers to "cv2T2
" ifT1
it is the same type asT2
, orT1
is the base classT2
. "cv1T1
" refers to "cv2T2
" if itT1
refers toT2
, and cv1 is the same cv qualification as a higher cv qualification than cv2.
Then we have:
(5) A reference to type "cv1
T1
" is initialized with an expression of type "cv2T2
" as follows:
- If the reference is an lvalue reference and an initializer expression
- is an lvalue (but not a bitfield), and "cv1
T1
" is referentially-compatible with "cv2T2
,"- ..
then the reference is bound to the lvalue initializer value in the first case and to the lvalue conversion result in the second case
- Otherwise, this reference must be an lvalue reference to a non-volatile const type (i.e., cv1 must be
const
), or the reference must be an rvalue reference.
The "then" case does not apply because int
it is not referential-compatible with double
. So we get to another case, which says that the result must be an rvalue reference. That is, the link must be either:
const double& dcr = a; // lvalue reference to a non-volatile const type
double&& drr = a; // rvalue reference
But that's not what your code is doing - hence the error. In fact, what you want to do is explicitly mentioned in the standard as a counter example at the same point:
int i = 2;
double& rd3 = i; // error: type mismatch and reference not const
source to share
The compiler is looking Swap(int&, double&)
because you have supplied int
as the first parameter and double
as the second, and it cannot find it.
You can do the following:
int a = 5;
double b = 10.3;
double c = a * 1.0;
Swap<double>(a, c);
Essentially, you have declared a function that wants to refer to two double
s. When the compiler converts int
to double
, it creates a temp. You don't want a temporary function because it can change the value (that's what the link means).
Also makes sense to swap a floating point integer?
source to share