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

为何decltype会为具名值推导为右值引用?

具名右值引用的decltype推导疑问
#include <iostream>
 
class A {};

void TestValueCategory(A& ft_) {
    (void)ft_;
    std::cout << "   TestValueCategory(&)...\n";
}
    
void TestValueCategory(const A& ft_) {
    (void)ft_;
    std::cout << "   TestValueCategory(const &)...\n";
}
    
void TestValueCategory(A&& ft_) {
    (void)ft_;
    std::cout << "   TestValueCategory(&&)...\n";
}

template<typename U>
void Forwarder(U&& u_) {
    TestValueCategory(std::forward<U>(u_));
}
    
auto funcRVOauto() {
    return A();
}
 

int main()
{
    auto&& rv = funcRVOauto();
    std::cout << "\nrv addr [" << (void*)&rv << "]\n";
    std::cout << "rv Value-category is" << (std::is_rvalue_reference<decltype(rv)>::value == true ? "" : " NOT") << " rvalue ref\n";
    Forwarder(rv); //Forwarder(std::move(rv) prints TestValueCategory(&&), as expected
}

程序运行输出:

rv addr [0x7fff9434cc6f]
rv Value-category is rvalue ref
   TestValueCategory(&)...

在main函数中,rv是具名值(可获取其地址,并非x值),为何decltype能推导其原始值类别为右值引用?


这是因为decltype的推导规则分两种核心场景:

  1. 当操作数是变量名、函数名或成员访问表达式时,decltype直接返回该实体的声明类型,完全不考虑它在表达式中的值类别。
  2. 当操作数是带括号的表达式(比如decltype((rv)))或其他复杂表达式时,decltype才会根据表达式的值类别推导:左值表达式推导为左值引用,右值表达式推导为右值引用。

回到示例代码:

  • auto&& rv = funcRVOauto(); 中,funcRVOauto()返回临时对象(右值),因此auto&&被推导为A&&(右值引用类型),这就是rv的声明类型。
  • decltype(rv)直接取rv的声明类型,所以得到A&&,因此std::is_rvalue_reference<decltype(rv)>::value返回true。

而rv作为具名的右值引用变量,它在表达式中的值类别是左值——所有具名变量,不管声明类型是左值还是右值引用,在表达式中都会被当作左值处理。所以调用Forwarder(rv)时,std::forward会将其作为左值转发,最终匹配左值引用版本的TestValueCategory;如果用std::move(rv)将其强制转换为右值,就会匹配右值引用版本的函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 20:34:52