为什么对引用的 const 引用会失去其常量性?

Kan*_*ane 46 c++ language-lawyer

鉴于此代码:

#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
}
Run Code Online (Sandbox Code Playgroud)

为什么会const T &j变成int &jif T=int&?会发生什么const

eer*_*ika 33

没有引用引用这样的东西,即没有T & &.

给定const T&where Tis int&,该类型会折叠为int&.

const 会发生什么?

也没有 const 引用这样的东西,即没有T & const(不要与对 const 的引用混淆,const 确实存在并且通常通俗地称为 const 引用)。不能修改引用(这与修改引用的对象不同),因此常量没有意义。const 在这里被简单地忽略了。

标准规则(来自最新草案):

[dcl.ref] 如果 typedef-name ([dcl.typedef], [temp.param]) 或 decltype-specifier ([dcl.type.simple]) 表示类型 TR 是对类型 T 的引用,尝试创建类型“对 cv TR 的左值引用”会创建类型“对 T 的左值引用”,而尝试创建类型“对 cv TR 的右值引用”会创建类型 TR。[ 注意:此规则称为参考折叠。— 尾注 ]

这里 cv 指的是 cv 限定符,即 const 和 volatile。

澄清为什么这适用于模板参数:

[temp.param] 标识符不跟随省略号的类型参数将其标识符定义为 typedef-name ...


PS 指定引用折叠的方式是完美转发工作的部分原因。


son*_*yao 16

Given const T&,本身const是合格的T。当T是 时int&const T表示const引用(即int& const);实际上是没有const引用的,(注意不是引用constie const int&),引用初始化后不能重新绑定。在这种情况下,const限定符将被忽略。

引用类型不能在顶级是 cv 限定的;声明中没有与此相关的语法,如果将限定符添加到 typedef-name 或 decltype 说明符或类型模板参数,则忽略它。


Mat*_* M. 8

我总是建议人们采用East-const风格,总是将 放在const它所符合的右边(东),而你只是遇到了一个让一切变得不同的情况。

使用 West-const 表示法,您已编写:

template<typename T>
void modify(const T &j){ j = 42; } // j has type int&
Run Code Online (Sandbox Code Playgroud)

int&T,你是天真地进行文本替换,就好像它是一个宏,思考j作为const int && j。事实并非如此。

使用 East-const 表示法,你会写:

template<typename T>
void modify(T const& j){ j = 42; }
Run Code Online (Sandbox Code Playgroud)

替换int&T,您会得到int& const& j:注意const根本不在您认为的位置?

而现在,这个世界又变得有意义了。你有一个引用的常量引用int

  • 引用是const,所以你不能修改引用本身......但是你永远不能。
  • int不是const,所以你可以修改int

CQFD。