c ++:关于转发引用的混淆

时间:2016-04-25 13:39:51

标签: c++ c++11 move move-semantics forwarding-reference

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

1 个答案:

答案 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已不再推断。你基本上说让TX。因此,如果TX,那么T &&X&&,您就会收到错误:p,其类型现在为X&&无法绑定到左值。

霍尔特还补充道:

  

另请注意,由于sortFunc的声明,这不会   即使您没有指定函数模板参数也可以工作   明确地

我倾向于同意他,但我需要进一步调查以确保这一点。