我在Scott Meyers的C ++ 11中阅读了关于转发参考的this(写得非常好)文章。
现在,请关注本文的这一部分:
template <class... Args> void emplace_back(Args&&... args); // deduced parameter types ⇒ type deduction; ... // && ≡ universal references
因此,与其他情况相比,省略号不会使&&
成为右值参考,但它仍然是通用参考。
根据我的理解,当我们有通用引用时,我们可以调用函数传递rvalue和lvalues(哇,太酷了!)
现在,我已经实现了这个功能:
template <typename ReturnType, typename... Args>
ReturnType callFunction(MemFunc<ReturnType, Args...> memFunc, Args&& ... args) { ...
所以(使用与前一个示例相同的逻辑),&&
表示转发引用。
但如果我尝试拨打此电话:
typedef vector<double> vecD;
vecD vec;
mem.callFunction<vecD, vecD>(sortFunc, vec);
编译器会抱怨You cannot bind an lvalue to an rvalue reference
为什么会这样?
整个代码:
#include <functional>
#include <vector>
using namespace std;
struct MultiMemoizator {
template <typename ReturnType, typename... Args>
ReturnType callFunction(std::function<ReturnType(Args...)> memFunc, Args&&... args) {
}
};
typedef vector<double> vecD;
vecD sort_vec (vecD const& vec) {
return vec;
}
int main()
{
vecD vec;
std::function<vecD(vecD)> sortFunc(sort_vec);
MultiMemoizator mem;
mem.callFunction<vecD, vecD>(sortFunc, vec);
}
答案 0 :(得分:8)
首先,请使用“转发参考”而不是“通用参考”。它更好地代表了它是什么以及它的用途是什么。
首先要注意的是,并非每个&&
都是转发引用。它也可以是右值参考。
简单来说,T&&
是一个转发参考,当且仅当:
T
是简单(简单如下所示)类型(例如vector<int>&&
或vector<T>&&
不 a转发参考)。T
被推断出来。在您的示例中,Args
未推断出来。这是因为您在调用它时显式指定了函数模板参数Args
:
mem.callFunction<vecD, vecD>(sortFunc, vec);
^~~~
让我们使用更简单易懂的东西:
让我们设置场景:
struct X {};
template <class T>
auto foo(T&& p) {}
在接下来的2个电话中,我们有转发参考:
X x;
foo(x);
foo(X{});
在第一个中,T
将被推断为X&
,并且通过折叠规则:X& &&
变为X&
,因此我们有左值引用。正如您所料。
在第二个中,T
将被推断为X
,并且折叠规则X &&
变为X&&
,因此我们有一个左值参考。
但是当你这样称呼时:
foo<X>(x);
T
已不再推断。你基本上说让T
为X
。因此,如果T
为X
,那么T &&
为X&&
,您就会收到错误:p
,其类型现在为X&&
无法绑定到左值。
另请注意,由于sortFunc的声明,这不会 即使您没有指定函数模板参数也可以工作 明确地
我倾向于同意他,但我需要进一步调查以确保这一点。