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

时间:2015-10-21 18:36:44

标签: c++ templates c++11

我看到了类似

的用法
#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)

1 个答案:

答案 0 :(得分:2)

扣除T&&的规则很棘手。

它们旨在推断出T&&“转发参考”(或“通用参考”)。

首先,引用崩溃。假设你有一个未知类型X.现在不推断出X

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

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

我们将X设置为intint&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&

如果您将X&&传递给T&&,则会将T推断为XT&&也变为X&&

在他们两个之间,在推导的上下文中,template<class T> void foo(T&&t)是一个通用引用(好吧,现在称为转发引用)。

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

这允许一个模板处理l和r值,并且如果需要,可以使用std::forward和类似机器的行为略有不同。

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