为什么C++禁止将T1 &&绑定到T2左值,当T1与T2引用相关时(并且T1和T2不是类类型)?

6jjcrrmo  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(78)

我在探索这个问题:既然有了char * x,为什么const char * && rc2 = x不能编译?
我找到了dcl.init.ref#5.4.4,它说(当我们将T1 &&绑定到T2左值时,其中T2不是类类型),如果T1T2是引用相关的,那么如果引用是右值引用,则初始化表达式不应该是左值。
为什么会有这样的规定?这条规则想要避免什么?
我清楚地知道像int i; int && ri = i;这样的绑定是非法的,但我这里的问题是,我期望const char * && rc2 = static_cast<const char *>(x);,其中static_cast<const char *>(x)应该是一个可以绑定到右值引用的右值。
既然int i; double && rd = i;有效,为什么char * x; const char * && rc2 = x;无效?

8ehkhllq

8ehkhllq1#

该规则不仅适用于以下情况,

int x;
int&& r = x;

而且

const int x = 0;
int&& r = x;

在这里,我们在类型上没有完全匹配:引用想要绑定到int,但初始化表达式的类型为const int。就像我们不希望第一个例子创建一个临时int对象(x的副本),然后将r绑定到它一样,在第二个例子中,我们也不希望通过复制x来创建临时int对象。
或者类似地

struct Base { /* ... */ };
struct Derived : Base { /* ... */ };
Derived d;
Base&& b = d;

这个想法是,如果你有一个引用绑定,只要引用是适当的类型(即,一个左值引用而不是右值引用),并有适当的cv限定,那么这可能是程序员的错误。创建临时对象通常不是所需的行为。
参照关系抓住了“可能是一种直接约束”的概念。
至于你提到的这个案例:

char * x; const char * && rc2 = x;

同样的逻辑适用于:引用相关性告诉您,这与有效的引用绑定“太接近”。如果将引用的类型更改为const char* const&,则绑定将有效。

nr9pn0ug

nr9pn0ug2#

这个问题似乎可以归结为
为什么引用相关的类型被特殊对待?:)
我不知道这个问题的答案,我怀疑它没有明确写在标准中。
我可以做一个疯狂的假设:

  • 如果xy有引用相关的类型,这意味着你可以以同样的方式在内存中布局它们,所以让x成为y的引用是可能的,因此像X && x = y;这样的东西会让你感到惊讶,因为编辑x会改变y,你不会期望从一个右值引用(除非你有意识地std::move d y,很明显)。
  • 另一方面,如果xy具有与引用无关的类型,那么像X && x = y;这样的东西需要将yY转换为X,这样你就真正得到了一个临时的,在内存中的其他地方,X&& * 可以 * 绑定。

下面是对原始问题的回答以及一些编辑

给定char * x,为什么const char * && rc2 = x不能编译?
因为这就像任何其他SomeType x; const SomeType && r = x;,即。它试图将一个左值绑定到一个rvlue引用上,而这对于你引用的标准是不允许的。
我的问题是,为什么会有这样的规定?这条规则想要避免什么?
这并不是说它想避免什么。这只是使右值引用真正有用的方法。
毕竟

  • 如果一个右值引用可以绑定到右值和左值,那么它与const&没有什么不同,那么为什么要引入它呢?
  • 如果一个右值引用只能绑定到左值,那么它和(非const&没有什么不同,那么为什么要引入它呢?
int i;
double && rd = i;

工作,因为rd是对double的引用,但初始化器是int,所以临时double通过将i转换为double来实现,that 是临时的。

**请注意,在这两个语句之后,您不应该期望修改rd会导致修改i,实际上也不会发生这种情况。

另一方面,您最初提到的情况更类似于(原因是即使在您的情况下类型不同,char*const char*,它们仍然是引用相关的,因为conv.qual

int i;
int && rd = i; // illegal

如果这是工作,那么上面的两个要点将适用,你会看到对rd的编辑反映在i中。
但是,如果你这样做

int i;
int && rd1 = static_cast<int>(x);
int && rd2 = static_cast<int&&>(x);

rd1被绑定到一个临时的(因为expr.static.cast#1),而不是i,而rd2i有写访问权。

相关问题