为何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的推导规则分两种核心场景:
- 当操作数是变量名、函数名或成员访问表达式时,decltype直接返回该实体的声明类型,完全不考虑它在表达式中的值类别。
- 当操作数是带括号的表达式(比如
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
相关产品推荐
相关产品推荐

