c ++:对转发引用的困惑

c++: confusion about forwarding reference

我阅读了 this(写得非常好)关于 Forwarding Reference in C++11 的文章,作者是 Scott Meyers。

现在,重点关注文章的这一部分:

template <class... Args>
void emplace_back(Args&&... args); // deduced parameter types ⇒ type deduction;
...                                // && ≡ universal references

因此,与其他情况相比,省略号不会使 && 成为右值引用,但它仍然是通用引用。

据我了解,当我们拥有通用引用时,我们可以调用传递右值和左值的函数(哇,太酷了!)

现在,我实现了这个功能:

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);
}

所以首先,请使用 "forwarding reference" 而不是 "universal reference"。它更好地代表了它是什么以及它的预期用途。

首先要注意的是,并非每个 && 都是转发引用。它也可以是右值引用。

简单来说,T&& 是转发参考当且仅当:

  • Tsimple(简单如下所示)类型(例如 vector<int>&&vector<T>&&不是转发参考)。
  • 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。因此,如果 TX,则 T &&X&&,并且您会遇到错误: p whose type is now X&& cannot bind to an左值。


霍尔特还补充道:

Also note that because of the declaration of sortFunc, this would not work even if you did not specify the function template arguments explicitely.

我倾向于同意他的观点,但我需要进一步调查才能确定这一点。