add_rvalue_reference实现疑问:函数类型推导为何得左值引用而非右值?
函数类型右值引用推导的差异原因解析
核心差异:表达式值类别 vs 纯粹类型构造
第一个测试代码的断言失败,和自定义模板与标准库结果一致的原因,本质是函数调用表达式的decltype推导规则与直接构造类型别名的逻辑差异:
1. 函数调用表达式的decltype推导逻辑
当函数返回类型为引用类型(包括右值引用)时,函数调用表达式的结果是左值。根据decltype的推导规则:
- 对左值表达式使用
decltype,最终会得到对应的左值引用类型
在第一个测试中:
template <typename T> T &&test_rvalue_reference(int);
显式指定T为void ()(函数类型)后,函数的返回类型是void ()&&(函数右值引用),但调用test_rvalue_reference<void ()>(0)得到的是左值表达式,因此decltype推导结果为void (&)()(函数左值引用),这导致第一个断言与标准库add_rvalue_reference_t<void ()>(结果为void ()&&)不匹配。
2. 自定义模板的类型构造逻辑
自定义add_right_value_reference模板是直接通过类型别名构造结果,完全不受表达式值类别的影响:
- 当
T为函数类型void ()时,T&&直接构造出函数右值引用类型void ()&& - 模板通过SFINAE机制判断是否能合法构造右值引用(比如针对
void这类不允许右值引用的类型会触发偏特化),其逻辑与标准库add_rvalue_reference_t完全对齐,因此断言全部通过。
代码细节对比
第一个测试的关键矛盾点:
// 函数返回类型是void ()&&,但调用表达式是左值,decltype推导为左值引用 static_assert(is_same_v<decltype(test_rvalue_reference<void ()>(0)), void (&)()>); // 断言成立
自定义模板的正确逻辑:
template <typename T> struct add_right_value_reference<T, true> { using type = T &&; // 直接构造类型,得到void ()&&,不受表达式影响 };
补充说明
函数类型的右值引用是合法的C++类型,标准库add_rvalue_reference_t<void ()>的结果就是void ()&&。第一个测试的混淆点在于混淆了函数返回的引用类型和表达式的value category:前者是类型本身,后者决定了decltype的推导结果。
内容的提问来源于stack exchange,提问作者Jonny0201
相关产品推荐
相关产品推荐

