-2

我阅读了 Scott Meyers 的这篇(写得非常好)关于C++11 中的转发参考的文章。

现在,关注本文的这一部分:

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

1 回答 1

8

所以首先,请使用“转发参考”而不是“通用参考”。它更好地代表了它是什么以及它的预期用途是什么。

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

简而言之T&&,当且仅当:

  • T是一个简单的(简单如下所示)类型(例如vector<int>&&orvector<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&,因此我们有一个左值引用。如你所料。

在第二个中,TX通过折叠规则推导出为,因此我们有一个右值引用X &&X&&

但是当你这样称呼它时:

foo<X>(x);

T不再推演。你基本上说 let Tbe X。所以 if Tis Xthen T &&is X&&,并且您遇到错误:p其类型现在X&&无法绑定到左值。


霍尔特还补充说:

另请注意,由于 sortFunc 的声明,即使您没有明确指定函数模板参数,这也不起作用。

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

于 2016-04-25T13:55:25.493 回答