为什么T const&&不是转发参考?

时间:2016-09-03 05:46:20

标签: c++ templates const move-semantics forwarding-reference

在模板的上下文中,以下"引用折叠"规则适用:

template <typename T>
void foo(T && t)
{
    //T&  &   -> T&
    //T&  &&  -> T&
    //T&& &   -> T&
    //T&& &&  -> T&&
}

为什么语言禁止&#34;普遍参考&#34;来自const资格赛?

template <typename T>
void foo(T const && t)

如果类型已经解决了参考(4个案例中的3个),那似乎是有意义的。

我确信这个想法与该语言的其他一些设计方面不相容,但我无法完全看清楚。

4 个答案:

答案 0 :(得分:4)

最初,右值参考提案表示如果P是“右值参考类型”,则会发生转换。 However, a defect report后来注意到了

  

此外,请考虑这种情况:

template <class T> void f(const T&&);
...
int i;
f(i);
     

如果我们在这种情况下将T推断为int&,则f(i)会调用f<int&>(int&),这似乎违反直觉。我们希望调用f<int>(const int&&)。因此,我们希望措辞澄清,14.8.2.1 [temp.deduct.call]第3段中的A&扣除规则仅适用于T&&而不是cv T&&作为注意目前暗示。

似乎有一段时间段const T &&TU&,已转换为const U&。这被改为与另一条规则一致,即const T T U&U&保留T(忽略引用的cv限定符)。因此,当您将上述示例中的int&推断为int&时,函数参数将保持const int& f<int>(const int&&)

在缺陷报告中,记者表示“我们更愿意调用const int&&”,但在缺陷报告中没有提供任何理由。我可以想象,原因在于,在不引入与其他规则不一致的情况下修复此问题似乎过于复杂。

我们还应该记住,缺陷报告是在rvalue引用仍然可以绑定到左值的时候进行的 - 即this.opendoc = function () { var h = 500, w = 500; var billhref = '/pages/bill.html'; var openedwidow = window.open(billhref, '', 'scrollbars=1,height='+Math.min(h, screen.availHeight)+',width='+Math.min(w, screen.availWidth)+',left='+Math.max(0, (screen.availWidth - w)/2)+',top='+Math.max(0, (screen.availHeight - h)/2)); }; 可以绑定到int左值。这只是在Dave&amp; amp;道格,“RValue参考的安全问题”出现了。所以,在我看来,一个有效的演绎(当时)比一个演绎更有价值,而这个演绎只是反直觉和掉线的限定词。

答案 1 :(得分:2)

参考已经发生了这种情况;如果您的TU const &,则T &&将折叠为U const &。术语“通用引用”确实意味着通用引用:您不需要在其中指定const来获得常量引用。

如果你想拥有一个真正的通用引用机制,你需要你的T &&能够成为各种引用,将各种常量。并且,T &&就是这样做的。它折叠到所有四种情况:l值和r值引用,以及const和非 - const

另一种方式解释,const ness是类型的属性,而不是引用,即当你说T const &时,你实际上是在谈论U &,其中U 1}}是T const&&也是如此(尽管对const的r值引用不太有用)。

这意味着,如果您希望将您的通用引用折叠为U const &,只需将其传递给您想要的类型:U const &,它就会崩溃到那个。< / p>

更直接地回答您的问题:该语言不会“禁止”在声明通用引用时使用const。这就是说,如果你改变声明通用引用的机制甚至一点点 - 即使在constT之间插入一个低&& - 那么你就不会有一个(字面上)“普遍”的参考,因为它不会接受任何东西。

答案 2 :(得分:0)

为什么您认为该语言不允许使用const r值引用?

在下面的代码中,将要打印什么?

#include <iostream>

struct Foo 
{
  void bar() const & 
  {
    std::cout << "&\n";
  }

  void bar() const &&
  {
    std::cout << "&&\n";
  }
};

const Foo make() { 
  return Foo{}; 
}

int main()
{
  make().bar();
}

答案:

&&

为什么呢?因为make()返回一个const对象,在这个上下文中它是一个临时对象。因此r值引用const。

答案 3 :(得分:-2)

Template argument deduction有一个特殊情况,即“rvalue引用cv-unqualified模板参数”。转发/通用引用依赖于这种非常特殊的情况。有关详细信息,请参阅链接文章中的“从函数调用中扣除”部分。

请注意,在模板参数推断之前,将删除所有顶级cv限定符;但是,引用从不具有顶级cv限定符,并且上述规则不适用,因此特殊规则也不适用。 (与指针相反,没有“const引用”,只有“引用const”)