简体   繁体   English

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

[英]Why a const volatile reference cannot be bound to an rvalue reference?

I would like to understand why a const volatile reference cannot be bound to an rvalue reference? 我想理解为什么const volatile引用不能绑定到右值引用? What is the rational reason to prohibit such a conversion? 禁止这种转换的理由是什么?

In the following code I comment out lines that do not compile: 在下面的代码中,我注释掉了不编译的行:

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?
}

Here a more realistic scenario, that fails to compile for a similar reason: 这是一个更现实的场景,由于类似的原因无法编译:

#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 &
 }

In this code, I would have expected that g<volatile int>(const volatile&) accept any argument. 在这段代码中,我原本期望g<volatile int>(const volatile&)接受任何参数。

An other edit, for a more concret example: 另一个编辑,更具体的例子:

#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());
  //... 
  //...
 }

There must have a good reason for this limitation no? 这个限制必须有充分理由吗?

The correct question should sound as " Why a const volatile reference cannot be bound to an rvalue ?" 正确的问题应该是“ 为什么const volatile参考不能绑定到rvalue ?”

The following code doesn't compile either, although no rvalue references are directly involved: 以下代码也不编译,但没有直接涉及右值引用:

const volatile int& cvr = 0;

This answer to a related question cites the relevant section of the standard: 这个答案的相关问题,引用标准的相关部分:

Per [dcl.init.ref] /5, for a reference to be initialized by binding to an rvalue, the reference must be a const non- volatile lvalue reference, or an rvalue reference: Per [dcl.init.ref] / 5,对于通过绑定到rvalue初始化的引用,引用必须是const非易失volatile左值引用或rvalue引用:

— Otherwise, the reference shall be an lvalue reference to a non-volatile const type (ie, cv1 shall be const ), or the reference shall be an rvalue reference. - 否则,引用应是对非易失性const类型的左值引用(即, cv1应为const ),或者引用应为右值引用。

My guess is that this restriction has historical roots in the C++98 standard where rvalues were limited to temporaries, that were fully managed by the compiler. 我的猜测是,这种限制在C ++ 98标准中具有历史根源,其中rvalues仅限于临时数,完全由编译器管理。 The compiler can place the temporary at any address or register of its choice, and treating it as a volatile object with observable reads doesn't make sense. 编译器可以将临时文件放在其选择的任何地址或寄存器中,并将其视为具有可观察读取的易失性对象没有意义。 In the new standard an lvalue reference can be converted to an rvalue reference with std::move() , however as a result it gets the old properties assumed for rvalues, ie that their exact memory address is insignificant, and thus cannot have the volatile attribute assigned to it. 在新标准中,可以使用std::move()将左值引用转换为右值引用,但结果它获得了为rvalues假定的旧属性,即它们的确切内存地址无关紧要,因此不能具有volatile分配给它的属性。

Technically this restriction is not a very limiting one, since you can effectively bind a const volatile reference to an rvalue through an extra level of indirection: 从技术上讲,这种限制并不是非常有限的,因为您可以通过额外的间接级别将const volatile引用有效地绑定到rvalue:

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

// This does compile
const int& cr = 0;
const volatile int& cvr = cr;

The literal reason is that [dcl.init.ref] forbids such a declaration: 字面上的原因是[dcl.init.ref]禁止这样的声明:

A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows: 对类型“cv1 T1”的引用由类型“cv2 T2”的表达式初始化,如下所示:
- If the reference is an lvalue reference and the initializer expression [...] - 如果引用是左值引用和初始化表达式[...]
- Otherwise, the reference shall be an lvalue reference to a non-volatile const type (ie, cv1 shall be const), or the reference shall be an rvalue reference. - 否则,引用应是对非易失性const类型的左值引用 (即,cv1应为const),或者引用应为右值引用。

The next level reason is just a guess (and a problem with asking why questions): such a declaration makes no sense. 下一个原因只是一个猜测(以及询问为什么问题的问题):这样的声明毫无意义。 The purpose of volatile is to make all reads and writes observable behavior. volatile的目的是使所有读取和写入可观察的行为。 If you're initializing a reference to const volatile from a temporary, you're now the owner of the lifetime of this object. 如果您正在初始化对临时的const volatile的引用,那么您现在是该对象生命周期的所有者。 But you can't write to it. 但是你不能写信给它。 And neither can anyone else. 其他任何人都不能。 So what does volatile convey? 那么volatile传达是什么?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM