我在探索这个问题:既然有了char * x
,为什么const char * && rc2 = x
不能编译?
我找到了dcl.init.ref#5.4.4,它说(当我们将T1 &&
绑定到T2
左值时,其中T2
不是类类型),如果T1
与T2
是引用相关的,那么如果引用是右值引用,则初始化表达式不应该是左值。
为什么会有这样的规定?这条规则想要避免什么?
我清楚地知道像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;
无效?
2条答案
按热度按时间8ehkhllq1#
该规则不仅适用于以下情况,
而且
在这里,我们在类型上没有完全匹配:引用想要绑定到
int
,但初始化表达式的类型为const int
。就像我们不希望第一个例子创建一个临时int
对象(x
的副本),然后将r
绑定到它一样,在第二个例子中,我们也不希望通过复制x
来创建临时int
对象。或者类似地
这个想法是,如果你有一个引用绑定,只要引用是适当的类型(即,一个左值引用而不是右值引用),并有适当的cv限定,那么这可能是程序员的错误。创建临时对象通常不是所需的行为。
参照关系抓住了“可能是一种直接约束”的概念。
至于你提到的这个案例:
同样的逻辑适用于:引用相关性告诉您,这与有效的引用绑定“太接近”。如果将引用的类型更改为
const char* const&
,则绑定将有效。nr9pn0ug2#
这个问题似乎可以归结为
为什么引用相关的类型被特殊对待?:)
我不知道这个问题的答案,我怀疑它没有明确写在标准中。
我可以做一个疯狂的假设:
x
和y
有引用相关的类型,这意味着你可以以同样的方式在内存中布局它们,所以让x
成为y
的引用是可能的,因此像X && x = y;
这样的东西会让你感到惊讶,因为编辑x
会改变y
,你不会期望从一个右值引用(除非你有意识地std::move
dy
,很明显)。x
和y
具有与引用无关的类型,那么像X && x = y;
这样的东西需要将y
从Y
转换为X
,这样你就真正得到了一个临时的,在内存中的其他地方,X&&
* 可以 * 绑定。下面是对原始问题的回答以及一些编辑
给定
char * x
,为什么const char * && rc2 = x
不能编译?因为这就像任何其他
SomeType x; const SomeType && r = x;
,即。它试图将一个左值绑定到一个rvlue引用上,而这对于你引用的标准是不允许的。我的问题是,为什么会有这样的规定?这条规则想要避免什么?
这并不是说它想避免什么。这只是使右值引用真正有用的方法。
毕竟
const&
没有什么不同,那么为什么要引入它呢?const
)&
没有什么不同,那么为什么要引入它呢?工作,因为
rd
是对double
的引用,但初始化器是int
,所以临时double
通过将i
转换为double
来实现,that 是临时的。**请注意,在这两个语句之后,您不应该期望修改
rd
会导致修改i
,实际上也不会发生这种情况。另一方面,您最初提到的情况更类似于(原因是即使在您的情况下类型不同,
char*
与const char*
,它们仍然是引用相关的,因为conv.qual)如果这是工作,那么上面的两个要点将适用,你会看到对
rd
的编辑反映在i
中。但是,如果你这样做
rd1
被绑定到一个临时的(因为expr.static.cast#1),而不是i
,而rd2
对i
有写访问权。