std::is_same具有左值和右值引用的结果
std::is_same result with lvalue and rvalue reference
我在玩std::is_same实用函数与右值和左值引用的组合时,遇到了一个奇怪的行为。
考虑一下这个函数模板,它检查变量t的类型。
我正在使用VS 2013:
struct Test {};
template < class T> void h(T && t)
{
cout << " Is type &&: " << std::is_same<decltype(t), T &&>::value << endl;
cout << " Is type &: " << std::is_same<decltype(t), T &>::value << endl;
}
我观察到以下输出:
h(Test()); // is type && : 1 is type & : 0
目前这是正常的,因为Test()是一个临时对象,参数h中的通用引用解析为r值引用(&&=&)
但考虑一下:
Test myTest;
h(myTest); // is type && : 1 is type & : 1 !!!
相同的结果,如果我写:
Test &myTest = Test():
h(myTest); // is type && : 1 is type & : 1 !!!
与相同
Test &&myTest = Test():
h(myTest); // is type && : 1 is type & : 1 !!!
我是不是错过了什么?在我看来,这完全是一团糟:)VS 2013中是否不完全支持rvalue-reference/deltype功能?
谢谢你的帮助
罗曼
Romain,这很容易。让我们考虑以下情况:
Test myTest;
h(myTest); // is type && : 1 is type & : 1 !!!
在h内部,T是Test&
,并且T是类型Test& &&
,即Test&
。进行测试时,std::is_same<decltype(t), T &&>
为true,因为Test& &&
是Test&
,而t
类型是Test&
。
std::is_same<decltype(t), T &>
也是真的,因为t
类型是Test&
,而T&
是Test&&
,即Test&
。
仔细应用引用折叠规则在这里会有所帮助。
关于为什么内部的h()T是Test&
类型。原因是它是唯一一个与实际参数匹配的T类型。T不能简单地是Test
&将不会绑定(匹配)类型为Test
的左值(因为这是参数类型)。但是,由于引用折叠规则的原因,Test& &&
会。
我将从这里开始:
template < class T> void h(T && t)
{
std::cout << " Is type &&: " << std::is_same<decltype(t), T &&>::value << 'n';
std::cout << " Is type &: " << std::is_same<decltype(t), T &>::value << 'n';
}
在第一个测试中,您询问decltype(t)
是否与T&&
相同。
对于变量,decltype(variable)
是该变量的声明类型。看看t
是如何声明的——它就是T&&
。
毫不奇怪,decltype(t)
与T&&
相同,因为T&& t
被声明为T&&
。
无论T
是什么,这都是真的。因此,无论你通过哪种类型的T
,你都会在这条线上获得true。
抓住这个。理解这一点。您无法为T
匹配的任何类型都可能使第一行永远无法打印1
。如果您对第一行感到困惑,请回到它正在执行std::is_same< T&&, T&& >::value
的事实。无论T&&
的规则是什么,双方都是一样的。
但等等,你说,T&&
不是一个右值参考吗?嗯,通常。如果类型类型T
是引用类型,则应用引用折叠规则。当T=X&
变为X&
而不是X&&
时的T&&
。左值引用胜过右值引用。
通过特殊的推导规则,这就是转发引用(又称通用引用)的动力。
当您将类型为X
的左值传递给h
时,它将推导出T=X&
。
当您将类型为X
的右值传递给h
时,它将推导出T=X
。
在第一种情况下,T&&
变成X&
,在第二种情况下变成X&&
。
在你的具体例子中,Test()
是Test
类型的右值,这意味着h(Test())
推导出T=Test
,我们得到T&&
=Test&&
,而T&
=Test&
。代码打印1然后打印0,因为T&&
(又名decltype(t)
,又名Test&&
)与T&&
相同,但与T&
不同。
在第二种具体情况中,h(myTest)
将myTest
作为左值(即使它被声明为Test&&
,它也是一个左值,因为它有一个名称)。则T
为Test&
,T&&
为Test&
,T&
为Test&
。函数打印出1然后1,因为T&&
(又名decltype(t)
,又名Test&
)与T&&
和T&
相同。
要解决您的问题,请执行以下操作:
template < class T> void h(T && t)
{
using rawT = std::remove_reference_t<T>;
std::cout << " Is type &&: " << std::is_same<decltype(t), rawT &&>::value << 'n';
std::cout << " Is type &: " << std::is_same<decltype(t), rawT &>::value << 'n';
}
并且你得到了你期望的输出。
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- c++ lambda:柯里和函数:使用按值捕获与按引用捕获返回不同的结果
- C++ 获取函数在常量引用中按值返回的结果
- 取消引用指向整数的指针时获得不同的结果
- 按值传递变量与按引用传递变量具有相同的结果
- 如果结果存储在变量中forward_as_tuple然后在 std::apply 中使用之前丢失右值引用
- 在我的C++链表实现中取消引用节点指针,给出意想不到的结果
- 传递右值引用结果编译错误unique_ptr
- std::具有自定义比较函数结果的排序函数错误:必须调用对非静态成员函数的引用
- 对 std::atomic::load 的结果使用结构取消引用 (->) 运算符是否安全
- 未给出预期结果的引用
- C++宏中相互引用的奇怪结果
- 强制转换为父类对象而不是引用时会出现哪些不良结果
- 为什么"decltype(i+j)"的结果不是右值引用?
- c++按值传递、按引用传递或按值传递结果
- 简单的代码,看似随机的结果——这是由于过时的引用造成的吗
- 取消引用无效指针但不使用结果是否是C++中的未定义行为
- 取消引用运算符给出的结果与具有 void* 的数组偏移运算符不同
- 在取消引用的函数指针上使用时,std::is_function的求值结果为何为false
- std::is_same具有左值和右值引用的结果