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

jus*_*rld -2 c++ move move-semantics c++11 forwarding-reference

我看了这个约(令人难以置信的好写的)文章转发参考用C斯科特迈尔斯++ 11.

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

template <class... Args>
void emplace_back(Args&&... args); // deduced parameter types ? type deduction;
...                                // && ? universal references
Run Code Online (Sandbox Code Playgroud)

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

根据我的理解,当我们有通用引用时,我们可以调用函数传递rvalue和lvalues(哇,太酷了!)

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

template <typename ReturnType, typename... Args>
ReturnType callFunction(MemFunc<ReturnType, Args...> memFunc, Args&& ... args) { ...
Run Code Online (Sandbox Code Playgroud)

因此(使用与前一示例相同的逻辑)&&意味着转发引用.

如果我试着打电话:

typedef vector<double> vecD;
vecD vec;
mem.callFunction<vecD, vecD>(sortFunc, vec);
Run Code Online (Sandbox Code Playgroud)

编译器会抱怨 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);
}
Run Code Online (Sandbox Code Playgroud)

bol*_*lov 8

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

首先要注意的是,不是每个&&都是转发参考.它也可以是右值参考.

简单来说,T&&当且仅当:

  • T是一个简单的(如图所示下一个简单)类型(因此例如vector<int>&&或者vector<T>&&转发参考).
  • T推断出来.

在你的例子Args中没有推断出来.那是因为你Args在调用它时显式指定了函数模板参数:

mem.callFunction<vecD, vecD>(sortFunc, vec);
                       ^~~~
Run Code Online (Sandbox Code Playgroud)

让我们使用更简单的东西来更好地理解:

让我们设置场景:

struct X {};

template <class T>
auto foo(T&& p) {}
Run Code Online (Sandbox Code Playgroud)

在接下来的2个电话中,我们有转发参考:

X x;
foo(x);

foo(X{});
Run Code Online (Sandbox Code Playgroud)

在第一个,T将被推断为X&和通过折叠规则:X& &&变成X&,因此我们有一个左值引用.正如你所料.

在第二个,T将推断为X和折叠规则X &&成为X&&,因此我们有一个右值引用.

但是当你这样称呼时:

foo<X>(x);
Run Code Online (Sandbox Code Playgroud)

T不再推断.基本上,你说让TX.所以,如果TX那么T &&就是X&&,你有错误:p其类型是现在X&&不能绑定到左值.


霍尔特还补充说:

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

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