我在学习通用(转发)引用时发现了这个问题。代码如下。
#include <iostream> // std::cout
#include <type_traits>
template <class T> // deductions among universal reference
void fun(T &&b) // fold reference, maintain const
{
std::cout << b << " ";
std::cout << std::is_const<T>::value << " ";
std::cout << std::is_lvalue_reference<T>::value << " ";
std::cout << std::is_rvalue_reference<T>::value << std::endl;
}
int main()
{
int a = 1;
fun(a); // lvalue: T=int&
fun(std::move(a)); // rvalue: T=int
const int ca = 1;
fun(ca); // const_lvalue: T=int& (why no const?)
fun(std::move(ca)); // const_rvalue: T=const int
int &la = a;
fun(la); // lvalue_ref: T=int&
int &&ra = 1;
fun(ra); // rvalue_ref: T=int& (r_ref is an l_val)
fun(std::forward<decltype(ra)>(ra)); // rvalue_ref + perfect forwarding T=int
const int &cla = a;
fun(cla); // const_lvalue_ref: T=int& (no const?)
const int &&cra = 1;
fun(cra); // const_rvalue_ref: T=int& (no const?)
return 0;
}
其结果如下。可以看出,当输入参数是lvalue
时,在解析T
的类型时,const
被丢弃。然而,当它是r_value
时,const
被保持。
此外,当我尝试使用cppinsights运行这段代码时,它会生成4
模板专门化。
/* First instantiated from: insights.cpp:18 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void fun<int &>(int & b)
{
}
#endif
/* First instantiated from: insights.cpp:19 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void fun<int>(int && b)
{
}
#endif
/* First instantiated from: insights.cpp:22 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void fun<const int &>(const int & b)
{
}
#endif
/* First instantiated from: insights.cpp:23 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void fun<const int>(const int && b)
{
}
#endif
从结果中可以看出,const
在cppinsights中的解析过程后被维护。
有人能告诉我为什么我的代码和cppinsights的结果不一样吗?(为什么我的代码中的l_value
被推导为T&
而不是const T&
?)
换句话说,问题的正确答案是什么:从universal reference
推导const
是否会被丢弃?
2条答案
按热度按时间1tu0hz3e1#
当
T
是从带有左值参数的转发引用推导出来的,那么T
是左值引用类型,并且对于任何引用类型总是
false
,因为引用类型不能是const
限定的。你真正感兴趣的是引用的类型是否是“lvalue/rvalue-reference to X”,其中X
是某种const
限定类型,即是否是
true
当我们通俗地说引用是const
限定的,我们实际上是指这个,而不是引用类型本身实际上是const
限定的。ut6juiuv2#
const
永远不会被隐式丢弃,你使用std::is_const
测试某个东西是否“是const”的代码只是有缺陷。std::is_const
不考虑引用类型的常量:考虑一下你的代码中发生了什么:
当绑定到
const L
类型的左值时,转发引用T&&
将T
推导为const L&
。引用折叠后,T&&
就变成了const L&
。要使代码得到预期的结果,必须用途: