我遵循了一些C ++教程,令人沮丧的是,源材料声明无法进行此特定函数调用,但根本没有解释原因;
template<typename T>
void Swap(T &a, T &b){
T temp;
temp = a;
a = b;
b = temp;
}
现在我创建一个显式模板函数实例化并传入a
和b
;
int a = 5;
double b = 10.3;
Swap<double>(a, b);
然后抛出以下编译器错误;
无法转换&#39; a&#39; (键入&#39; int&#39;)键入&#39; double&amp;&#39;
我唯一的预感是,这是因为规则表明rvalue不能绑定到非const引用,但是,如果T &a
只是一个别名,它就是不是右边的本身,是吗?我的隐式演员是创建一个临时的,它不能绑定到T &a
?这是发生了什么?
temp
是一个左值。它可能只有函数范围,但确实存在。那么为什么它不允许隐式转换加倍,然后将引用a分配给temp
?意图看起来很清楚。我不太了解参考作为参数。如果a
被分配给临时值,这是一个左值,那么这是不允许的呢?
我假设我甚至在这里正确的轨道上。
修改
第二个例子;
int a = 5;
double &d = a; // invalid initialization of reference of type 'double&' from expression of type 'int'
然而;
int a = 5;
const double &d = a; //valid
答案 0 :(得分:5)
直观地说,交换a
和b
应该有效,因为编译器可以在int
和double
之间进行转换。但是,在实践中,请考虑编译器必须执行的操作才能执行您所要求的操作。
您从模板开始:
template<typename T>
void Swap(T &a, T &b){
T temp = a;
a = b;
b = temp;
}
要为double
实例化它,编译器会创建一个类似这样的函数:
void Swap(double& a, double& b) {
double temp = a;
a = b;
b = temp;
}
这些是引用参数 - 它们指向内存中的实际位置,而不是别名或副本。在引擎盖下,引用的行为类似于指针,因此如果有帮助,您可以将此功能视为与此类似:
void Swap(double* a, double *b);
换句话说,Swap
需要引用(指针)两个内存中的双精度数 - 两个8字节的内存部分(假设double占用8个字节)。作为聪明而直观的人,我们知道Swap
的实现并不真正需要两个8字节的内存部分,但这就是它的声明方式,因此编译器强制执行它
要制作一个可以处理混合参数的Swap版本,您必须执行以下操作:
template<typename T1, typename T2>
void Swap(T1& a, T2& b) {
T1 tmp(a);
a = b;
b = tmp;
}
答案 1 :(得分:3)
你要做的是有效:
int a = 5;
double& dr = a;
管理标准中参考初始化的规则在§8.5.3中。首先,一些定义:
(4)给定类型“ cv1
T1
”和“ cv2T2
,”“ cv1 { {1}}“与参考相关的与” cv2T1
“如果T2
与T1
的类型相同,或者T2
是T1
的基类。 “ cv1T2
”参考兼容与“ cv2T1
”如果T2
为< em>与参考相关的与T1
和 cv1 具有相同的cv资格,或者比 cv2 更高的cv资格。
然后,我们有:
(5)类型“ cv1
T2
”的引用由类型为“ cv2T1
”的表达式初始化,如下所示:
- 如果引用是左值引用和初始化表达式
- 是左值(但不是位字段),“ cv1
T2
”与“ cv2 {{1}”引用兼容},”- ..
然后引用绑定到第一种情况下的初始化表达式lvalue和第二种情况下转换的左值结果
- 否则,引用应该是对非易失性const类型的左值引用(即 cv1 应为
T1
),或者引用应为右值引用。< / p>
“then”案例不适用,因为T2
与const
不是参考兼容的。所以我们转到另一个案例,它说明结果应该是 rvalue 引用。也就是说,引用应为:
int
但这不是你的代码所做的 - 因此错误。实际上,您想要做的事情在标准中明确提到作为同一项目中的反例:
double
答案 2 :(得分:0)
编译器正在寻找Swap(int&, double&)
,因为您提供了int
作为第一个参数,而double
作为第二个参数,它无法找到一个参数。
您可以执行以下操作:
int a = 5;
double b = 10.3;
double c = a * 1.0;
Swap<double>(a, c);
基本上,您声明了一个想要引用两个double
的函数。当编译器将int
转换为double
时,它会创建一个临时的。你的功能并不想要一个临时的,因为它可能会修改这个值(参考意味着什么)。
此外,交换带浮点的整数是否有意义?