c – 为什么模板化的右值引用接受左值?

我看到了类似的用法

#include <iostream>
#include <functional>
using namespace std;

template<typename FN>
void Foo(FN&& Fn)
{
    Fn();
}


void b()
{
    cout << "2." << endl;
}

int main() 
{
    Foo([](){ cout << "1." << endl; });
    Foo(&b);

    auto c = []() { cout << "3." << endl; };

    Foo(c);

    std::function<void(void)> d = c;

    Foo(d);

    return 0;
}

我很确定’c’是一个左值,但我可以相信有一些lambda型演绎shenanigans.但我几乎100%肯定,d是左值.

如果函数接受rvalue,为什么模板化的东西有效,但d是左值?

此外,为什么会像那样写Foo的签名而不仅仅是

template<typename FN>
void Foo(FN Fn)

最佳答案 T&& amp;& amp; amp;& amp;很棘手

它们的设计目的是为了推导T&& amp; “转发参考”(或“通用参考”).

首先,参考崩溃.假设您有一个未知类型X.现在不推导出X.

然后,如果我们检查以下类型的变量:

typedef X x0;
typedef X& x1;
typedef X const& x2;
typedef X&& x3;

我们将X设置为int,int&,int const&和int&&,我们得到:

X is --->  int         int&      int const&      int&&
X          int         int&      int const&      int&&
X&         int&        int&      int const&      int&
X const&   int const&  int&      int const&      int&
X&&        int&&       int&      int const&      int&&

live example.

下一部分附带扣除规则.如果你通过X&对T&&在推导的上下文中,T被推断为X&.这导致T&&成为X&通过上述参考折叠规则.类似的事情发生在X const&amp ;.

如果你通过X&&对于T&&,它推断T为X. T&&成为X&&同样.

在它们中的两个之间,在推导的上下文中,模板 void foo(T& t)是一个通用引用(现在称为转发引用).

您可以使用std :: forward< T>(t)恢复t的r / l值类别,因此名称转发引用.

这允许一个模板处理l和r值,并且如果需要,可以使用std :: forward和类似的机制稍微不同地表现.

只处理rvalues需要额外的工作:你必须使用SFINAE或其他重载(可能使用= delete).只处理左值很容易(只需用T&推断).

点赞