为什么对引用的常量引用会失去其恒定性?
Why does a const reference to a reference lose its constness?
给定此代码:
#include <iostream>
template<typename T>
void modify(const T &j){ j = 42; } // j has type int&
int main()
{
int i = 10;
modify<int&>(i); // T=int&
std::cout << i; // 42 is printed
}
如果T=int&
,为什么const T &j
会变得int &j
?const
会怎样?
没有引用这样的东西,即没有T & &
。
给定一个T
int&
const T&
,该类型折叠为int&
。
康斯特会发生什么?
也没有常量引用这样的东西,即没有T & const
(不要与引用常量混淆,常量确实存在,并且通常俗称常量引用(。不能修改任何引用(这与修改引用的对象不同(,因此恒常性没有意义。这里只是忽略了常量。
标准规则(来自最新草案(:
[dcl.ref] 如果 typedef-name ([dcl.typedef], [temp.param]( 或 decltype-specifier ([dcl.type.simple]( 表示对类型 T 的引用的类型 TR,则尝试创建类型"对 cv TR 的左值引用"将创建类型"对 T 的左值引用",而尝试创建类型"对 cv TR 的 rvalue 引用"将创建类型 TR。 [ 注意:此规则称为引用折叠。 — 尾注 ]
这里的 cv 是指 cv 限定符,即常量和易失性。
要阐明为什么这适用于模板参数,请执行以下操作:
[temp.param] 标识符不遵循省略号的类型参数将其标识符定义为 typedef-name ...
附言指定引用折叠的方式是完美转发工作的部分原因。
给定const T&
,const
在T
本身上是限定的。当T
int&
时,const T
表示const
引用(即int& const
(;实际上没有const
引用,(请注意,它不是对const
的引用,即const int&
(,引用在初始化后无法重新绑定。在这种情况下,const
限定符将被忽略。
引用类型不能在顶级进行 cv 限定;声明中没有语法,如果将限定添加到 typedef-name 或 decltype 说明符或类型模板参数中,则会忽略该限定符。
我总是建议人们采用 East-const 风格,即始终将const
放在它所限定的右侧(东部(,而您只是遇到了它会产生一切差异的情况。
使用West-const表示法,您已经编写了:
template<typename T>
void modify(const T &j){ j = 42; } // j has type int&
用int&
代替T
,你天真地在执行文本替换,就好像它是一个宏一样,并认为j
是const int && j
。其实不然。
使用East-const表示法,您可以编写:
template<typename T>
void modify(T const& j){ j = 42; }
用int&
代替T
,你会得到int& const& j
:注意到const
根本不在你认为的地方吗?
而现在,世界又变得有意义了。您有一个对int
引用的常量引用:
- 引用是
const
的,所以你不能修改引用本身...但话又说回来,你永远做不到。 int
不是const
,所以你可以修改int
。
CQFD。
- 将对象数组的引用传递给函数
- 什么时候在C++中返回常量引用是个好主意
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 指针类型类成员的动态强制转换的恒定性是什么?
- 为什么对引用的常量引用会失去其恒定性?
- 对指针和恒常性兼容性的引用
- 引用类型的数据成员提供有关恒常正确性"loophole"
- 运算符的要求<恒定性在标准::stable_sort
- 模板参数推导由于恒定性不一致而失败
- 为什么模板参数失去恒定性?
- 为什么普遍引用不保持其论点的恒定性
- 是否可以使用 SFINAE 检测类方法的恒定性?
- 在模板中强制转换为引用似乎会抛弃恒定性
- 在分配对象时保持恒定性
- 常量成员函数中模板成员的恒定性
- 变量的恒定性及其生存期
- 尊重恒定性,同时避免在堆上重新分配
- const_cast转换为左值引用不会消除恒常性
- 参考类成员的恒定性
- 当函数参数常量引用 T 时,为什么 T 的模板参数推导'skips'数组元素的恒定性?