使用std :: forward与auto &&是正确的事情

Ser*_*ger 8 c++ c++11

试图了解是否使用std::forwardauto&&变量是通过这些变量,允许移动的正确途径.

假设有一个功能:

void moveWidget(Widget&& w);
Run Code Online (Sandbox Code Playgroud)

和调用者 - 两个变量来引用rvalue和lvalue:

Widget w;
auto&& uniRefLV = w;            // lvalue initialiser, 
                                // uniRefLV's type is Widget&

auto&& uniRefRV = std::move(w); // rvalue initialiser, 
                                // uniRefRV's type is Widget&&
Run Code Online (Sandbox Code Playgroud)

我们知道类型的变量auto&&通用引用,因为存在类型推导.这意味着双方uniRefRVuniRefLV普遍引用.

在我的例子中,显然uniRefRVrvalue并且uniRefLV左值,但从概念上讲它们都是通用引用,如果定义不同,它们可以表示rvaluelvalue.

现在,我想调用moveWidget()并完善这些通用引用类型.该指南(由Scott Meyers撰写)说:

传递和返回右值引用通过std::move,普遍引用通过std::forward.

除非我完全误解了指南,否则使用起来似乎合乎逻辑std::forward.但是让我们考虑所有可能的选择:

// (1) std::move:
moveWidget(std::move(uniRefLV)); // Compiles and looks fine
                                 // but violates the guideline?
                                 // (unconditionally casts lvalue to rvalue)

moveWidget(std::move(uniRefRV)); // Same as above - but not an issue here
                                 // as we cast rvalue to rvalue

// (2) std::forward with Widget:
moveWidget(std::forward<Widget>(uniRefLV)); // Compiles, follows the guideline
                                            // but doesn't look right - what if
                                            // we didn't know Widget's type?

moveWidget(std::forward<Widget>(uniRefRV)); // Same as above

// (3) std::forward with decltype:
moveWidget(std::forward<decltype(uniRefLV)>(uniRefLV)); // Fails to compile! (VC10)
                                                        // follows the guideline
                                                        // has nice and short syntax :)

moveWidget(std::forward<decltype(uniRefRV)>(uniRefRV)); // Compiles fine
Run Code Online (Sandbox Code Playgroud)

你认为我们应该把两个引用uniRefLVuniRefRV平等,我们应该使用哪三个选项完美转发?

R. *_*des 11

你误解了指南.或者至少从字面上看它.

我认为这里有三个重要的事情需要实现.

首先,这里所有类型都是已知的.对于通用引用的建议主要适用于具有模板的通用代码,如果某些内容是或者采用左值引用或右值引用,则根本不知道.

其次,该函数采用右值引用:您必须传递右值.期.这里别无选择.

而符合逻辑的结论是,你并不想传递一个普遍的参考:无论你传递必须是一个右值,它永远是一个左值.通用引用可以是左值(如果它们被实例化为左值引用).传递一个通用引用意味着"我不知道这是什么样的引用,我可以将它作为rvalue或左值传递,所以我正在传递它,就像我得到它一样".这个问题的情况更像是"我确切地知道我必须通过什么,所以这就是我将要通过的".


Seb*_*edl 5

让我们假设这种情况并不像看起来那样简单。而不是giveMeInt像这样:

template <typename T>
typename complex_computation<T>::type giveMeSomething(T t);
Run Code Online (Sandbox Code Playgroud)

取而代之的是moveMe,您实际上拥有一个通用的参考,因此不需要无条件的参考std::move

template <typename T>
void wantForwarded(T&&);
Run Code Online (Sandbox Code Playgroud)

现在,您实际上需要完美的转发。

auto&& uniRef = giveMeSomething(iDontKnowTheTypeOfThis);
wantForwarded(std::forward<decltype(uniRef)>(uniRef);
Run Code Online (Sandbox Code Playgroud)