最近我编写了一个函数,它正在对双数进行一些处理,但是由于一些变化,我需要对整数进行相同的处理,所以用下面给出的更简单的例子简化长篇故事:
void display(double& arg)
{
std::cout << arg << std::endl;
}
int main()
{
int inum = 10;
display(inum);
return 0;
}
我发现上面的代码没有编译并且给出错误“类型的引用”double&amp;“(不是const-qualified)不能用类型”int“的值初始化,因为错误非常直观所以我修改了代码并将显示函数的参数更改为const double&amp; arg,一切似乎都正常工作。所以我的问题是
“const double&amp;”中究竟发生了什么?案件?需要完整的解释吗?
现在,在阅读了所提供的一些解释和问题链接后,我明白转换产生的rvalue和rvalue不能绑定到临时值,所以我寻找的唯一推理是为什么转换产生rvalue?
答案 0 :(得分:3)
以下是我看到的错误示例:error: invalid initialization of non-const reference of type 'double&' from an rvalue of type 'double'
显然抱怨double&
(这是display
函数的参数类型)无法使用类型为double
的右值进行初始化。好吧,inum
被传递给函数,但它的类型是int
。但是,int
可以隐式转换为double
,这种情况正在发生。转换产生rvalue
(即临时)double
,但暂时不能绑定到非const引用。
将其更改为void display(const double& arg)
是有效的,因为一切都与上面说明的相同。但是,右值可以绑定到 const 引用。
我没有官方标准,但以下引用来自n4296 draft:
4次标准转化[转化]
1 标准转化是具有内置含义的隐式转化。第4条列举了全套这类 转换。标准转换序列是按以下顺序的一系列标准转换:
(1.1) - 来自以下集合的零或一次转换:左值到右值的转换,数组到指针的转换以及函数到指针的转换。
3 当且仅当声明T t = e时,表达式e可以隐式转换为类型T.形式良好, 对于一些发明的临时变量t(8.5)。
6 任何隐式转换的效果与执行相应的声明和初始化相同 然后使用临时变量作为转换结果。
答案 1 :(得分:1)
System.out.println
是对double的引用,它存在于其他地方。通常,您可以使用它来修改调用者提供的变量。但是,如果来电者提供了double&
的地址,并且您尝试将其视为int
,那么事情将会非常糟糕!编译器还禁止像double
一样调用像void bar(double&)
这样的函数,因为尝试修改临时值通常没有意义。
另一方面,使用bar(3.14)
,您保证不会更改值:您只是通过引用来获取它以避免复制,而不是修改它。因此,可以使用临时调用const double&
,如void foo(const double&)
:编译器传递临时地址,foo(3.14)
取消引用它以获取值,并在{{1}之后返回临时消失。
这就是这里发生的事情:当签名要求foo
,并且你提供foo
时,会创建一个临时双精度(从const double&
投射),其地址被传递到int
。
答案 2 :(得分:1)
如果inum
是double
,您的代码就会生效,因为您的参数是lvalue
(您可以使用其地址)。
如果您的函数签名为void display(const double& arg)
,那么它将起作用,因为提升的参数是临时的,您可以将const
引用绑定到临时的将其生命周期延长到const reference
标识符的范围。
如果您的函数签名为void display(double&& arg)
,那么它将起作用,因为提升的参数是临时的,您可以将rvalue
引用绑定到临时的将其生命周期延长到rvalue reference
标识符的范围。
上述两种方法之间的区别在于,您可以修改后者中的arg
及其C ++ 11及以上版本....
在C ++中,您不能将非const引用(特别是左值)绑定到临时引用。
会发生int
double
到void inc(double& x)
{ x += 0.1; }
int i = 0;
inc(i);
不允许引用临时工具的原始案例是 功能参数。假设这是允许的:
options
为什么我没有改变?