为什么const volatile引用不能绑定到右值引用?

Oli*_*liv 11 c++ c++11

我想理解为什么const volatile引用不能绑定到右值引用?禁止这种转换的理由是什么?

在下面的代码中,我注释掉了不编译的行:

int main(){
 int i=1;
 //const volatile int& cvi2=std::move(i); -> ERROR: why?
 const volatile int i2=0;
 //const volatile int& cvi3=std::move(i2);// -> ERROR: why?
}
Run Code Online (Sandbox Code Playgroud)

这是一个更现实的场景,由于类似的原因无法编译:

#include<iostream>
template<class T> void g(const T& b){
  //do usefull things
}
template<class T,class F> void f(T& a,F a_func){
  //do usefull things with a
  a_func(std::move(a));
}
int main(){
   int i=0;
   volatile int vi=1;
   f(i,g<int>); //OK no error;
   f(vi,g<volatile int>);//ERROR: can not convert volatile int to
                                 //const volatile int &
 }
Run Code Online (Sandbox Code Playgroud)

在这段代码中,我希望g<volatile int>(const volatile&)接受任何参数.

另一个编辑,更具体的例子:

#include <vector>
using usefull_type=int;
void set_communication_channel_to(volatile usefull_type* g,size_t n);
int main(){
  auto vect=
    std::vector<volatile usefull_type>(10,usefull_type{42});//->ERROR no known conversion
                                                      // from int to const volatile int &
  set_communication_channel_to(vect.data(),vect.size());
  //... 
  //...
 }
Run Code Online (Sandbox Code Playgroud)

这个限制必须有充分理由吗?

Leo*_*eon 8

正确的问题应该是" 为什么const volatile参考不能绑定到rvalue?"

以下代码也不编译,但没有直接涉及右值引用:

const volatile int& cvr = 0;
Run Code Online (Sandbox Code Playgroud)

这个答案的相关问题,引用标准的相关部分:

Per [dcl.init.ref]/5,对于通过绑定到右值来初始化的引用,引用必须const是非volatile左值引用或右值引用:

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

我的猜测是,这种限制在C++ 98标准中具有历史根源,其中rvalues仅限于临时数,完全由编译器管理.编译器可以将临时放置在其选择的任何地址或寄存器中,并将其视为具有可观察读取的易失性对象没有意义.在新标准中,左值引用可以转换为右值引用std::move(),但是因此它获得了为rvalues假定的旧属性,即它们的确切内存地址无关紧要,因此不能为其分配volatile属性.

从技术上讲,这种限制不是非常有限的,因为您可以const volatile通过额外的间接级别有效地绑定对rvalue 的引用:

// This doesn't compile
// const volatile int& cvr = 0;

// This does compile
const int& cr = 0;
const volatile int& cvr = cr;
Run Code Online (Sandbox Code Playgroud)


Bar*_*rry 5

字面原因是 [dcl.init.ref] 禁止这样的声明:

\n\n
\n

对类型 \xe2\x80\x9ccv1 T1\xe2\x80\x9d 的引用由 \xe2\x80\x9ccv2 T2\xe2\x80\x9d 类型的表达式初始化,如下所示:
\n - 如果引用是左值引用和初始化表达式 [...]
\n - 否则,引用应为非易失性 const 类型的左值引用(即 cv1 应为 const),或者引用应为右值引用。

\n
\n\n

下一级原因只是猜测(以及提出“为什么”问题的问题):这样的声明没有任何意义。目的volatile是让所有的读写行为都可观察到。const volatile如果您正在初始化临时对象的引用,那么您现在就是该对象生命周期的所有者。但你不能写它。其他人也不能。那么传达什么呢volatile

\n

  • @MM 关键是这种特殊用例不可能适用于编译器凭空产生的临时情况。 (2认同)
  • @MM:它不会是只读但可更改的位置,也不会是内存映射的只读硬件寄存器。它是由该行上的副本创建的临时文件。它_仅_存在于 C++ 程序中。“易失性”可能对它的复制源有意义,但对副本则不然。我不知道还能怎样向你表达。 (2认同)
  • @MM:你的损失。:) 其他人都明白了。 (2认同)