You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何C++ const引用会折叠为非const引用?如何限制其可修改性?

为什么A<int&>(x).get() = 43;能编译通过?如何让get()返回真正的const引用?

首先直接回答第一个问题:是的,这个行为完全是由C++的引用折叠规则导致的。

让我们拆解代码里的细节:
当你实例化A<int&>时,模板参数T被推导为int&。此时get()函数的返回类型const T&展开后是const (int&) &——这里要注意,C里引用本身不能被const修饰,所以const int&里的const是作用于引用指向的对象,而非引用本身。但当我们把T设为int&后,const T其实是试图给引用加const,这本身是无效的,再加上外层的&,就触发了引用折叠规则:
在C
中,引用的引用会按照以下规则折叠:

  • T& & → T&
  • T& && → T&
  • T&& & → T&
  • T&& && → T&&

所以const int& &最终会折叠成int&,这就意味着get()实际返回的是一个非const的左值引用,自然允许你对其返回值赋值,也就出现了代码里A<int&>(x).get() = 43;能编译通过的情况。


接下来解决第二个问题:如何让get()返回真正的const引用,禁止修改指向的值?

核心思路是:先移除T的引用属性,得到其底层的原始类型,再给这个原始类型加上const和引用,这样就能避免引用折叠导致const限定失效。

你可以借助C标准库的std::remove_reference_t(C14及以后可用,C++11可以用std::remove_reference<T>::type)来实现:

修改后的代码如下:

#include <iostream>
#include <type_traits> // 必须包含这个头文件来使用类型特性

template<typename T>
class A {
public:
    explicit A(T& x) : x_(x){}
    // 先移除T的引用,再给原始类型加const引用
    const std::remove_reference_t<T>& get() { return x_; }
private:
    T x_;
};

int main() {
    int x = 42;
    // A<int&>(x).get() = 43; // 现在这行会编译失败,因为返回的是const int&
    std::cout << x << '\n';
}

这样,当T是int&时,std::remove_reference_t<T>会得到int,所以get()的返回类型就变成了const int&——这是真正的const引用,不允许对其返回值进行赋值操作,完美达到了你的需求。

你也可以用类型别名让代码更清晰:

template<typename T>
class A {
    // 定义底层类型别名
    using underlying_type = std::remove_reference_t<T>;
public:
    explicit A(T& x) : x_(x){}
    const underlying_type& get() { return x_; }
private:
    T x_;
};

内容的提问来源于stack exchange,提问作者Jonathan Boccara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:43:30