为什么用指向非 const 的指针初始化的对 const 指针的右值引用不会创建临时对象并将其与其绑定?

Man*_*uel 6 c++ pointers reference rvalue-reference temporary-objects

如果我们想用不同的类型初始化引用,我们需要将其设置为 const (const type*),以便可以隐式生成临时对象并将引用绑定到 with。或者,我们可以使用右值引用并实现相同的[1]:

右值引用可用于延长临时对象的生命周期(注意,对 const 的左值引用也可以延长临时对象的生命周期,但不能通过它们进行修改):

[...]

样品

情况1

double x = 10;

int &ref = x; //compiler error (expected)
Run Code Online (Sandbox Code Playgroud)

案例2

double x = 10;
const int &ref = x; //ok
Run Code Online (Sandbox Code Playgroud)

案例3

double x = 10;
int &&ref = x; //ok
Run Code Online (Sandbox Code Playgroud)

如果我们尝试对 const 指针(const type* &)做同样的事情,并用非 const 指针(type*)初始化它,与我预期的不同,只有情况 2 有效。为什么情况3会导致编译器错误?为什么没有生成临时文件?

情况1

int x = 10;

int *pX = &x;

const int* &ref = pX; //compiler error (expected)
Run Code Online (Sandbox Code Playgroud)

案例2

int x = 10;
int *pX = &x;
const int* const &ref = pX; //ok (expected)
Run Code Online (Sandbox Code Playgroud)

案例3

int x = 10;
int *pX = &x;
const int* &&ref = pX; //compiler error (why?)
Run Code Online (Sandbox Code Playgroud)

在带有标志 -std=c++20 (和其他一些)的 gcc 12.1.0 和 clang 14.0.4 中,上面的情况 3 无法编译。

  • gcc : '错误: 无法将'const int*&&'类型的右值引用绑定到'int*'类型的左值''
  • clang: '错误: 对类型 'const int *' 的右值引用无法绑定到类型 'int *' 的左值

为什么在 int&、int&& 等情况下都运行良好,而在指针的情况下却出现编译器错误?我目前的知识是否存在一些不准确的地方?(我是新手)

如果我们对纯右值(int*)做同样的事情,一切都会很好

案例3

int x = 10;
//int *pX = &x;
const int* &&ref = &x; //ok (why?)
Run Code Online (Sandbox Code Playgroud)

相关问题:

<指向 const 对象的非常量指针的非常量引用>

<对指针的 const 引用未按预期运行>

  • 类似的问题,但都建议使用对 const (type* const &) 的引用。我想知道为什么右值引用不能与指针一起使用,但可以与 int 等一起使用,并且没有被问到。

< T&&(双与号)在 C++11 中意味着什么?>

  • r 值参考 (&&)

参考

[1] https://en.cppreference.com/w/cpp/language/reference

Art*_*yer 3

该标准有两种类型与参考相关的概念。这是通过两个相似的类型来实现的,这基本上意味着它们是否是具有相同数量的指针但可能不同的 cv 限定符的相同类型(例如,intconst int是相似的,int* const ** volatile并且volatile int** const *是相似的,并且至关重要的是int*const int*是相似的)。

标准指出([dcl.init.ref]p(5.4.4)):

如果T1与 参考相关T2

  • 如果引用是右值引用,则初始化表达式不应是左值。

由于const int* &&ref = pX;是右值引用,并且T1 = const int*与 引用相关T2 = decltype(pX) = int*,因此这适用,因此这是不允许的。const int* &&ref = std::move(pX);不会遇到这个问题,因为初始化器不再是左值。当然,显式进行 const 转换const int* &&ref = (const int*) pX;也是可行的。

据推测,这是不允许的const T x; T&& y = x;(绑定y到 的临时副本x),但由于标准的怪癖,它也扩展到了指针。