为什么不能将const volatile引用绑定到右值引用
Why a const volatile reference cannot be bound to an rvalue reference?
我想了解为什么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?
}
下面是一个更现实的场景,由于类似的原因无法编译:
#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 &
}
在这段代码中,我希望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());
//...
//...
}
这个限制必须有一个很好的理由,不是吗?
正确的问题应该是&;为什么const volatile引用不能绑定到右值?"
下面的代码也不能编译,尽管没有直接涉及到右值引用:
const volatile int& cvr = 0;
这个相关问题的答案引用了标准的相关部分:
/ [dcl.init。ref]/5,对于通过绑定到右值来初始化的引用,该引用必须是
const
非volatile
左值引用,或者是右值引用:—否则,引用应该是对非易失性const类型的左值引用(即cv1应该是
const
),或者引用应该是右值引用。
我猜这个限制在c++ 98标准中有历史根源,当时右值被限制为临时值,由编译器完全管理。编译器可以将临时对象放置在它选择的任何地址或寄存器中,将其视为具有可观察读的易失性对象是没有意义的。在新的标准中,可以用std::move()
将左值引用转换为右值引用,但结果是它获得了右值的旧属性,即它们的确切内存地址是无关紧要的,因此不能将volatile属性赋给它。
const volatile
引用绑定到右值:
// This doesn't compile
// const volatile int& cvr = 0;
// This does compile
const int& cr = 0;
const volatile int& cvr = cr;
字面上的原因是[dcl.init. net]Ref]禁止这样的声明:
对类型"cv1 T1"的引用由类型"cv2 T2"的表达式初始化,如下所示:
—如果引用是左值引用,且初始化表达式[…]
—否则,引用应该是对非易失const类型的左值引用(即cv1应该是const),或者引用应该是右值引用。
下一个层次的原因只是一个猜测(和问为什么问题的问题):这样的声明没有意义。volatile
的目的是使所有的读写行为都是可观察的。如果您从临时对象初始化对const volatile
的引用,那么您现在就是该对象生命周期的所有者。但是你不能给它写信。其他人也不能。那么volatile
传达了什么信息呢?
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 将常量指针引用绑定到非常量指针
- 运行时错误:引用绑定到类型为"int"的空指针
- 模板允许左值与右值引用绑定
- 运行时错误:引用绑定到类型"int"的未对齐地址0xbebebebebebebec6,这需要 4 个字节对齐 (stl_vector.h)
- 无法将类型"T&"的非常量左值引用绑定到类型"T"的右值 t++ std::atomic<T>
- 为什么定义复制构造函数会给我错误:无法将类型 'obj&' 的非常量左值引用绑定到类型为"obj"的右值?
- 将引用绑定到指针的语法是什么?(各种)
- 为什么我不能将常量左值引用绑定到返回 T&&&的函数?
- 为什么 VS 无法将右值引用绑定到指针?
- 出于什么原因,有必要将常量左值引用绑定到右值?
- 为什么此右值引用绑定到左值?
- 使用“void*”将右值引用绑定到左值
- 排序时引用绑定到 'value_type' 类型的 null 指针
- 无法将类型为"类名 &"的非常量左值引用绑定到类型为"类名"的右值
- 引用绑定和复制构造函数/移动构造函数
- 将引用绑定到类型的值会删除限定符 MULTISET
- 无法将类型"int&"的非常量左值引用绑定到类型为"int"的右值
- 多态变体,并将一种类型的引用绑定到另一种类型的引用
- C++17:是编译器为(静态存储持续时间)const引用绑定创建的可修改的临时对象(和存储)