【问题标题】:why const double reference can be assigned to int but not non const one?为什么 const 双引用可以分配给 int 而不是非 const one?
【发布时间】:2016-05-28 00:46:10
【问题描述】:

最近我编写了一个函数,它正在对双数进行一些处理,但由于一些变化,我需要对整数进行相同的处理,以便用下面给出的更简单的例子来缩短长话短说:

void display(double& arg)
{
    std::cout << arg << std::endl;
}
int main()
{
    int inum = 10;
    display(inum);
    return 0;
}

我发现上面的代码没有编译并给出错误“类型“double &”(非 const 限定)的引用不能用“int”类型的值初始化,因为错误非常直观,所以我修改了代码并将显示函数的参数更改为 const double& arg 并且一切似乎都正常工作。所以我的问题是

在“const double&”的情况下到底发生了什么?需要完整的解释吗?

现在在阅读了提供的一些解释和问题链接后,我了解到转换会产生右值,而右值不能绑定到临时变量,所以我要寻找的唯一理由是为什么转换会产生右值?

【问题讨论】:

  • 将其设为 const 允许编译器为参数构造一个临时变量。
  • 我相信临时变量是右值,但这里 inum 是左值,所以编译器也将左值转换为临时变量?
  • @Kapil 编译器需要一个双精度的左值。传递引用意味着被调用者可以修改值,并且传递临时作为引用是没有意义的,除非它是 const。否则被调用者可以进行修改而看不到任何效果,这只会让你感到困惑。

标签: c++ reference constants


【解决方案1】:

这是我看到的错误示例:error: invalid initialization of non-const reference of type 'double&amp;' from an rvalue of type 'double'

它显然在抱怨double&amp;(这是display 函数的参数类型)不能用double 类型的右值初始化。好吧,inum 已传递给函数,但它的类型是 int。但是,int 可以隐式转换为 double,并且正在发生这种情况。转换产生rvalue(即临时)double但临时不能绑定到非常量引用


将其更改为void display(const double&amp; arg) 有效,因为一切都与上面解释的一样。但是,右值可以绑定到 const 引用


我没有官方标准,但以下引用来自n4296 draft

4 次标准转换 [conv]

1 标准转换是具有内置含义的隐式转换。第 4 条列举了完整的此类 转换。标准转换序列是按以下顺序进行的标准转换序列:

(1.1) — 从以下集合进行零次或一次转换:左值到右值的转换、数组到指针的转换和函数到指针的转换。

3 表达式 e 可以隐式转换为类型 T 当且仅当声明 T t=e;形态良好, 对于一些发明的临时变量 t (8.5)。

6 任何隐式转换的效果都与执行相应的声明和初始化相同 然后使用临时变量作为转换的结果。

【讨论】:

  • 有什么方法可以识别转换产生右值吗?
  • 我不听你的问题。您是在询问有关隐式转换的标准参考吗?
  • 是的,这会很有帮助,因为我无法理解转换产生右值的原因
  • @Kapil 我没有正式副本,但我会查看我的草稿。但是,转换肯定不能产生左值(即,您可以获取地址的东西)。
【解决方案2】:

double&amp; 是对 double 的引用,它存在于其他地方。通常你会使用它来修改调用者提供的变量。但是,如果调用者提供了int 的地址,而您尝试将其视为double,那么您的情况会很糟糕!编译器还禁止使用诸如bar(3.14) 之类的临时值调用诸如void bar(double&amp;) 之类的函数,因为尝试修改临时值通常没有意义。

另一方面,对于const double&amp;,您承诺不会更改该值:您只是通过引用获取它以避免复制,而不是修改它。因此,可以使用临时调用void foo(const double&amp;),如foo(3.14):编译器传递临时地址,foo 取消引用它以获取值,并在foo 返回后临时消失。

这就是这里发生的事情:当签名调用const double&amp;,而您提供int,会创建一个临时双精度(从int 转换),并将其地址传递到display .

【讨论】:

    【解决方案3】:
    • 如果inumdouble,您的代码将起作用,因为您的参数是lvalue(您可以获取它的地址)。

    • 如果您的函数签名是 void display(const double&amp; arg),它将起作用,因为您的 promoted 参数是一个临时参数,您可以将 const 引用绑定到一个临时参数,从而延长其生命周期到const reference 标识符的范围内。

    • 如果您的函数签名是 void display(double&amp;&amp; arg),它将起作用,因为您的 promoted 参数是一个临时参数,您可以将 rvalue 引用绑定到一个临时参数,从而延长其使用寿命到rvalue reference 标识符的范围内。

    • 上述前两种方法的区别在于,后者可以修改arg,而它的C++11及以上......

    在 C++ 中,您不能将非 const 引用(特别是左值)绑定到临时对象。

    发生的情况是,intdouble 之间存在一个 implicit conversion

    引用Bo Personn's answer:

    不允许引用临时对象的原始案例是 函数参数。假设这是允许的:

    void inc(double& x)
    { x += 0.1; }
    
    int i = 0;
    inc(i);
    

    为什么我没有改变?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-15
      • 2018-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-01
      相关资源
      最近更新 更多