繁体   English   中英

带有左值和右值引用的std :: is_same结果

[英]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&& ,它也是一个左值,因为它有一个名称)。 然后TTest&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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM