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

时间:2016-01-07 16:00:00

标签: c++ c++11 rvalue-reference decltype

我正在使用std :: is_same实用程序函数与rvalue和lvalue引用一起玩,并且遇到了一种奇怪的行为。

考虑这个函数模板,它检查变量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值引用(&amp;&amp;&amp;&amp; =&amp;&amp;)

但请考虑一下:

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的功能?

感谢您的帮助

罗曼

2 个答案:

答案 0 :(得分:4)

罗曼,这很容易。让我们的条件如下:

4611686014132420609

Overflow!

666013


fin>>c;
for (i=1;i<=c;i++,p=0){
    fin>>a>>b;
    p=a*b;
    if (p/b==a)
        fout<<p<<"\n";
    else
        fout<<"Overflow"<<"\n";
}




return 0;
}

在h内,T为Test myTest; h(myTest); // is type && : 1 is type & : 1 !!! ,t为Test&,即Test& &&。进行测试时,Test&为真,因为std::is_same<decltype(t), T &&>Test& &&,而Test&类型为t

Test&也是如此,因为std::is_same<decltype(t), T &>类型为tTest&T&,即Test&&

仔细应用参考折叠规则有助于此。

有关为什么h()T内部为Test&类型的原因。原因是它是唯一与实际参数匹配的T类型。 T不能简单地Test&,因为Test&amp;&amp;不会绑定(匹配)类型Test的左值(因为这是参数类型)。但是,由于引用了折叠规则,Test将会出现。

答案 1 :(得分:1)

我将从这里开始:

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,你都会在那条线上得到真实。

抓住这个。明白这一点。您无法与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类型的右值,这意味着h(Test())推导T=Test,我们得到T&& = {{1 } {while Test&& = T&。代码打印1然后为0,因为Test&(又名T&&,又名decltype(t))与Test&&相同,但不是T&&

在第二个具体案例中,T&h(myTest)作为左值(即使它被声明为myTest,它也是左值,因为它有一个名称)。然后Test&&TTest&T&&Test&T&。该函数打印出1然后为1,因为Test&(又名T&&,又名decltype(t))与Test&T&&相同。

要解决您的问题,请执行以下操作:

T&

你得到了你期望的输出。