接受万能引用并返回const引用的函数出现异常行为
问题分析与解决方案
哈哈,这个问题我之前也踩过类似的坑!本质是C++里**转发引用(universal reference)**的引用折叠和模板参数替换规则在偷偷搞事情,导致你写的Const函数并没有返回你预期的const引用。
为什么原代码能编译运行?
当你传入左值int x = 5时,模板参数T会被推导为int&(因为T&&是转发引用,左值实参会触发模板参数推导为对应的左值引用类型)。这时候函数的返回类型const T&会展开成const int& &——根据C++的引用折叠规则,对引用的引用会合并为单一引用,而引用本身是不能被const修饰的,所以这个返回类型最终会被简化为int&。
换句话说,Const(x)实际上返回的是x的非const左值引用,自然可以被赋值,也就出现了你看到的x被修改为6的情况。
如何修改才能触发编译错误?
我们需要确保返回的是原始值类型的const引用,不受模板推导带来的引用类型干扰。核心思路是先剥离T的引用属性,再添加const和引用限定:
#include <type_traits> template <typename T> const std::remove_reference_t<T>& Const(T&& val) { return val; }
这里的std::remove_reference_t<T>会把T的引用属性完全剥离:
- 当传入左值
int x时,T推导为int&,std::remove_reference_t<T>就是int,返回类型为const int&; - 当传入右值
5时,T推导为int,std::remove_reference_t<T>还是int,返回类型依然是const int&。
现在再写int x = 5; Const(x) = 6;,编译器就会抛出类似**“assignment of read-only reference”**的编译错误,完全符合你想要的效果——禁止对返回值赋值。
如果你不想引入<type_traits>头文件,也可以用C++14的尾返回类型写法(本质和上面一致):
template <typename T> auto Const(T&& val) -> const typename std::remove_reference<T>::type& { return val; }
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

