从通用引用推导时是否会丢弃“const”?

pik*_*lee 3 c++ templates forwarding-reference

我在学习通用(转发)参考时发现了这个问题。代码如下。

\n
#include <iostream> // std::cout\n\n#include <type_traits>\n\ntemplate <class T> // deductions among universal reference\nvoid fun(T &&b)    // fold reference, maintain const\n{\n    std::cout << b << " ";\n    std::cout << std::is_const<T>::value << " ";\n    std::cout << std::is_lvalue_reference<T>::value << " ";\n    std::cout << std::is_rvalue_reference<T>::value << std::endl;\n}\n\nint main()\n{\n    int a = 1;\n    fun(a);            // lvalue: T=int&\n    fun(std::move(a)); // rvalue: T=int\n\n    const int ca = 1;\n    fun(ca);            // const_lvalue: T=int& \xef\xbc\x88why no const?\xef\xbc\x89\n    fun(std::move(ca)); // const_rvalue: T=const int\n\n    int &la = a;\n    fun(la); // lvalue_ref: T=int&\n\n    int &&ra = 1;\n    fun(ra);                             // rvalue_ref: T=int& (r_ref is an l_val)\n    fun(std::forward<decltype(ra)>(ra)); // rvalue_ref + perfect forwarding T=int\n\n    const int &cla = a;\n    fun(cla); // const_lvalue_ref: T=int& (no const?)\n\n    const int &&cra = 1;\n    fun(cra); // const_rvalue_ref: T=int& (no const?)\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

结果如下。可以看出,当输入参数为 时lvalue,在解析 的类型时const被丢弃T。不过,既然如此r_valueconst那就维持下去吧。

\n
1 0 1 0\n1 0 0 0\n1 0 1 0  <-const is discarded   //const_lvalue: T=int&\n1 1 0 0  <-const is maintained  //const_rvalue: T=const int\n1 0 1 0\n1 0 1 0\n1 0 0 0\n1 0 1 0  <-const is discarded  //const_lvalue_ref: T=int&\n1 0 1 0  <-const is discarded  //const_rvalue_ref: T=int&\n
Run Code Online (Sandbox Code Playgroud)\n

此外,当我尝试使用cppinsights运行此代码时,它会生成4 template professionalizations

\n
/* First instantiated from: insights.cpp:18 */\n#ifdef INSIGHTS_USE_TEMPLATE\ntemplate<>\nvoid fun<int &>(int & b)\n{\n\n}\n#endif\n\n/* First instantiated from: insights.cpp:19 */\n#ifdef INSIGHTS_USE_TEMPLATE\ntemplate<>\nvoid fun<int>(int && b)\n{\n\n}\n#endif\n\n/* First instantiated from: insights.cpp:22 */\n#ifdef INSIGHTS_USE_TEMPLATE\ntemplate<>\nvoid fun<const int &>(const int & b)\n{\n\n}\n#endif\n\n\n/* First instantiated from: insights.cpp:23 */\n#ifdef INSIGHTS_USE_TEMPLATE\ntemplate<>\nvoid fun<const int>(const int && b)\n{\n\n}\n#endif\n\n
Run Code Online (Sandbox Code Playgroud)\n

从结果可以看出,const是在cppinsights中解析过程后维护的。

\n

有人能告诉我为什么我的代码和 cppinsights 的结果不同吗?(为什么l_value在我的代码中被推导为T&而不是const T&?)

\n

换句话说,这个问题的正确答案是什么:const从 推导时是否会被丢弃universal reference

\n

use*_*522 8

T从带有左值参数的转发引用推导出来时,则T是左值引用类型并且对于任何引用类型

std::is_const<T>::value
Run Code Online (Sandbox Code Playgroud)

始终为false,因为引用类型不能被const- 限定。您真正感兴趣的是引用的类型是否为“对 X 的左值/右值引用”,其中X某些const限定类型,即是否

std::is_const<std::remove_reference_t<T>>::value
Run Code Online (Sandbox Code Playgroud)

true。当我们通俗地说引用是const- 限定的时,我们实际上是指这个,而不是引用类型本身实际上是const- 限定的。