[英]std::is_same result with lvalue and rvalue reference
我正在使用std :: is_same实用程序函数与rvalue和左值引用相结合,并遇到了一个奇怪的行为。
考虑这个函数模板,它检查变量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中的通用引用解析为ar值引用(&& && = &&)
但考虑一下:
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 / decltype的功能?
谢谢你的帮助
罗曼
罗曼,这很容易。 让我们考虑以下情况:
Test myTest;
h(myTest); // is type && : 1 is type & : 1 !!!
在h里面,T是Test&
,t是Test& &&
类型,即Test&
。 当你进行测试时, std::is_same<decltype(t), T &&>
为真,因为Test& &&
std::is_same<decltype(t), T &&>
是Test&
, t
type是Test&
。
std::is_same<decltype(t), T &>
也是如此,因为t
类型是Test&
,而T&
是Test&&
,它是Test&
。
仔细应用参考折叠规则有助于此。
有点为什么内部h()T是Test&
的类型。 原因是它是唯一与实际参数匹配的T类型。 T不能简单地Test
,因为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)
是decltype(variable)
的声明类型。 看看如何声明t
- 它是T&&
。
令人惊讶的是, decltype(t)
与T&&
相同,因为T&& t
被声明为T&&
。
无论T
是什么,都是如此。 所以无论你传递什么类型的T
,你都会在那条线上得到真实。
抓住这个。 明白这一点。 没有你能匹配T
类型可能会使第一行无法打印1
。 如果你对第一行感到困惑,那就回到它正在执行std::is_same< T&&, T&& >::value
的事实。 无论T&&
是什么规则,双方都是一样的。
但是,等等,你说,不是T&&
一个右值参考? 嗯,通常。 如果类型类型T
是引用类型,则应用引用折叠规则。 T&&
当T=X&
变为X&
不X&&
。 左值参考胜过右值参考。
这具有特殊的扣除规则,是转发引用(也称为通用引用)的动力。
当你将类型X
的左值传递给h
,它会推导出T=X&
。
当你将类型X
的右值传递给h
,它推导出T=X
在第一种情况下, T&&
变为X&
,而在第二种情况下,它变为X&&
。
在你的具体情况中, Test()
是一个类型为Test
的rvalue,这意味着h(Test())
推导出T=Test
,我们得到T&&
= Test&&
而T&
= Test&
。 代码打印1然后为0,因为T&&
(aka decltype(t)
,又名Test&&
)与T&&
相同,但不是T&
。
在第二个具体案例中, h(myTest)
将myTest
作为左值(即使它被声明为Test&&
,它也是一个左值,因为它有一个名称)。 然后T
是Test&
, T&&
是Test&
和T&
is 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';
}
并获得您期望的输出。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.