为什么`const T&`不确定是const?

xml*_*lmx 57 c++ templates const const-reference function-templates

template<typename T>
void f(T a, const T& b)
{
    ++a; // ok
    ++b; // also ok!
}

template<typename T>
void g(T n)
{
    f<T>(n, n);
}

int main()
{
    int n{};
    g<int&>(n);
}
Run Code Online (Sandbox Code Playgroud)

请注意:b是的const T&,++b没关系!

为什么const T&不确定是const?

Nat*_*ica 64

欢迎来到const和引用折叠.如果有const T&,则引用应用于T,以及const.你打电话g就好

g<int&>(n);
Run Code Online (Sandbox Code Playgroud)

所以你指定的Tint&.当我们对左值引用应用引用时,这两个引用会折叠为单个引用,因此int& &变为公正int&.然后我们从[dcl.ref]/1获得规则,该规则指出如果你应用于const引用它会被丢弃,所以int& const就变成int&(注意你实际上不能声明int& const,它必须来自typedef或模板) ).这意味着

g<int&>(n);
Run Code Online (Sandbox Code Playgroud)

你实际上在打电话

void f(int& a, int& b)
Run Code Online (Sandbox Code Playgroud)

而你实际上并没有修改常数.


如果你打电话g

g<int>(n);
// or just
g(n);
Run Code Online (Sandbox Code Playgroud)

T将是int,并且f本来会被标记为

void f(int a, const int& b)
Run Code Online (Sandbox Code Playgroud)

由于T不再是引用,const并且&get应用于它,并且您将尝试修改常量变量时​​收到编译器错误.

  • 让它更容易理解的一种方法是编写`T const&`而不是`const T&`(它是相同的),然后将`T`替换为`int &`. (9认同)
  • 这就是为什么存在像[`std :: add_lvalue_reference`](https://en.cppreference.com/w/cpp/types/add_reference)这样的类型特征,以确保以可预测的方式添加引用以防止这样做有点痛. (7认同)