我想了解为什么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());
//...
//...
}
这个限制必须有充分的理由吗?
答案 0 :(得分:8)
正确的问题听起来应该是&#34; 为什么const volatile参考不能绑定到右值?&#34;
以下代码也没有编译,但没有直接参与rvalue引用:
const volatile int& cvr = 0;
This answer相关问题引用了该标准的相关部分:
每 [dcl.init.ref] / 5,对于通过绑定到右值来初始化的引用,引用必须是
const
非 -volatile
左值参考或右值参考:- 否则,引用应该是对非易失性const类型的左值引用(即, cv1 应为
const
),或者引用应为右值引用。< / p>
我的猜测是,这种限制在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;
答案 1 :(得分:4)
字面上的原因是[dcl.init.ref]禁止这样的声明:
类型“cv1 T1”的引用由类型“cv2 T2”的表达式初始化,如下所示:
- 如果引用是左值引用和初始化表达式[...]
- 否则,引用应为非易失性const类型的左值引用(即,cv1应为const),或者引用应为右值引用。
下一个原因只是一个猜测(以及询问问题的原因):这样的声明没有意义。 volatile
的目的是使所有读取和写入可观察的行为。如果您正在初始化对const volatile
的临时引用,那么您现在是该对象生命周期的所有者。但是你不能写信给它。其他任何人都不能。那么volatile
传达了什么?