【问题标题】:cannot convert 'a' (type 'int') to type 'double&无法将“a”(类型“int”)转换为类型“double&”
【发布时间】:2015-01-06 20:16:05
【问题描述】:

我正在关注一些 C++ 教程,但令人沮丧的是,源材料指出无法进行此特定函数调用,但根本没有解释原因;

template<typename T>
void Swap(T &a, T &b){

    T temp;
    temp = a;
    a = b;
    b = temp;

}

所以现在我创建一个显式模板函数实例化并传入ab

int a = 5;
double b = 10.3;

Swap<double>(a, b);

然后引发以下编译器错误;

无法将“a”(类型“int”)转换为类型“double&”

我唯一的预感是,这是因为规定右值不能绑定到非常量引用的规则,但是,如果 T &amp;a 只是一个别名,它本身就不是右值,是吗?我的隐式演员正在创建一个临时的,它不能绑定到T &amp;a?是这样吗?

temp 是一个左值。它可能只有功能范围,但确实存在。那么为什么不允许隐式转换加倍,然后将引用 a 分配给temp?意图看起来很清楚。我不太理解作为参数的引用。如果 a 被分配给 temp,这是一个左值,那么这不是允许的吗?

这是假设我什至在正确的轨道上。

编辑:

第二个例子;

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

【问题讨论】:

  • 一个double 引用需要一个double 变量来引用。
  • 你希望a 的值在交换之后是多少?
  • @Paul Roub - 但是 C++ 不会隐式地将 int 强制转换为 double 以匹配引用类型吗?还是仅在变量的情况下如此?
  • @MartynShutt (变量或文字的)值可以通过强制转换进行转换,但在这里您需要传递一个双精度变量才能在函数内部使用。不仅仅是双重价值。该函数可以对它做任何事情,例如。分配双精度值或获取双精度指针
  • 这样说吧。你会写:int a; double &amp;b = a;?如果是这样,您不清楚参考文献 是什么

标签: c++ templates casting


【解决方案1】:

直观地说,交换ab 应该可以工作,因为编译器可以在intdouble 之间进行转换。但在实践中,请考虑编译器必须做什么才能完成您的要求。

你从一个模板开始:

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;
}

这些是 reference 参数 - 它们指向内存中的实际位置,而不是别名或副本。在引擎盖下,引用的行为类似于指针,因此如果有帮助,您可以将您的函数与此类似:

void Swap(double* a, double *b);

换句话说,Swap 需要引用(指针)到内存中的两个双精度 - 两个 8 字节的内存部分(假设双精度需要 8 个字节)。作为聪明而直觉的人,我们知道Swap 的实现并不真正需要两个 8 字节的内存部分,但这就是它的声明方式,也是编译器执行它的方式。

要制作可以处理混合参数的 Swap 版本,您必须执行以下操作:

template<typename T1, typename T2>
void Swap(T1& a, T2& b) {
    T1 tmp(a);
    a = b;
    b = tmp;
}

Demo.

【讨论】:

  • 需要 8 个字节?那么如果auint64_t 它会起作用吗?
  • @Barry - 我不认为这是“会”的情况。理论上可以,但任何严格遵循标准的编译器都不允许这样做。
  • @Barry - 不,显然;除非reinterpret_cast 或类似的,它需要一个 8 字节双精度,而不是 8 个任意字节。如果我不够清楚或不够准确,我深表歉意。
  • @JoshKelley 但这就是你的答案:“交换需要引用......到两个 8 字节的内存部分。”你没有提到类型。
【解决方案2】:

你想要做的是有效的:

int a = 5;
double& dr = a;

标准中管理引用初始化的规则在第 8.5.3 节中。首先,一些定义:

(4) 给定类型“cv1T1”和“cv2T2”,“cv1T1”是如果T1T2 的类型相同,或者T1T2 的基类,则reference-related 到“cv2 T2”。 “cv1 T1”与“​​cv2 T2引用兼容如果T1引用相关 到 T2 并且 cv1 的 cv 限定与 cv2 相同或更高。

那么,我们有:

(5) 对“cv1T1”类型的引用由“cv2T2”类型的表达式初始化,如下所示:

  • 如果引用是左值引用和初始化表达式
    • 是一个左值(但不是位域),并且“cv1 T1”与“cv2 T2,”是引用兼容的,
    • ..

那么引用在第一种情况下绑定到初始化表达式左值,在第二种情况下绑定到转换的左值结果

—否则,引用应为对非易失性 const 类型的左值引用(即,cv1 应为 const),或者引用应为右值引用。

“then”情况不适用,因为intdouble 的引用不兼容。所以我们转到另一种情况,它表明结果应该是一个 rvalue 引用。也就是说,引用应为:

const double& dcr = a; // lvalue reference to a non-volatile const type
double&& drr = a;      // rvalue reference

但这不是您的代码正在执行的操作 - 因此会出现错误。事实上,标准中明确提到了您想要做的事情,作为同一要点中的反例:

int i = 2;
double& rd3 = i; // error: type mismatch and reference not const

【讨论】:

  • 是的,这很清楚。我真的很想了解管理行为的规则,因为虽然我现在可以清楚地看到为什么不允许这样做,但我直觉上并不清楚。如果需要具体说明,我刚刚下载了最新标准的副本。
【解决方案3】:

编译器正在寻找Swap(int&amp;, double&amp;),因为您提供了int 作为第一个参数和double 作为第二个参数,但它找不到。

您可以执行以下操作:

int a = 5;
double b = 10.3;
double c = a * 1.0;
Swap<double>(a, c);

本质上,您声明了一个希望引用两个doubles 的函数。当编译器将int 转换为double 时,它会创建一个临时的。您的函数不需要临时的,因为它可能会修改值(这就是引用的意思)。

另外,用浮点数交换整数有意义吗?

【讨论】:

  • 编译器没有在寻找Swap(int&amp;, double&amp;),OP 正在显式调用Swap&lt;double&gt;
  • OP 在技术上调用Swap&lt;double&gt;(int, double)
猜你喜欢
  • 2019-08-18
  • 2020-05-03
  • 1970-01-01
  • 2017-02-08
  • 1970-01-01
  • 2020-06-01
  • 1970-01-01
  • 2014-01-07
相关资源
最近更新 更多