我看到了类似
的用法#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)
答案 0 :(得分:2)
扣除T&&
的规则很棘手。
它们旨在推断出T&&
“转发参考”(或“通用参考”)。
首先,引用崩溃。假设你有一个未知类型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&&
下一部分附带扣除规则。如果您在推断的上下文中将X&
传递给T&&
,则T
推断为X&
。这会导致T&&
成为X&
上述参考折叠规则。类似的事情发生在X const&
。
如果您将X&&
传递给T&&
,则会将T
推断为X
。 T&&
也变为X&&
。
在他们两个之间,在推导的上下文中,template<class T> void foo(T&&t)
是一个通用引用(好吧,现在称为转发引用)。
您可以使用t
恢复std::forward<T>(t)
的r / l值类别,因此可以使用名称转发参考。
这允许一个模板处理l和r值,并且如果需要,可以使用std::forward
和类似机器的行为略有不同。
只处理rvalues需要额外的工作:你必须使用SFINAE或其他重载(可能使用=delete
)。只处理左值很容易(只需推导T&
)。