c++ - 简要说明引用折叠规则请求 : (1) A& & -> A& , (2) A& && -> A& , (3) A&& & -> A& , 和 (4) A&& && -> A&&

标签 c++ stl

以下链接提供了 4 种形式的引用折叠(如果我是正确的,这些是仅有的 4 种形式):http://thbecker.net/articles/rvalue_references/section_08.html .

从链接:

  1. A& & becomes A&
  2. A& && becomes A&
  3. A&& & becomes A&
  4. A&& && becomes A&&


尽管我可以做出有根据的猜测,但我想简明地解释这些引用折叠规则背后的基本原理。

一个相关的问题,如果可以的话:这些引用折叠规则是否使用了在 C++11 由诸如 std::move() 等 STL 实用程序在内部进行, std::forward() ,等等,在典型的现实世界用例中? (注意:我特别询问是否在 C++11 中使用了引用折叠规则,而不是在 C++03 或更早版本中使用。)

我问这个相关的问题是因为我知道诸如 std::remove_reference 这样的 C++11 实用程序。 , 但不知道是否引用相关实用程序如 std::remove_reference在 C++11 中经常使用,以避免需要引用折叠规则,或者它们是否与引用折叠规则一起使用。

最佳答案

引用折叠规则(除了 A& & -> A& ,它是 C++98/03)的存在有一个原因:允许完美转发工作。

“完美”转发意味着有效地转发参数,就好像用户直接调用了函数一样(减去省略,被转发破坏)。用户可以传递三种值:lvalues、xvalues 和 prvalues,并且接收位置可以通过三种方式获取值:按值、通过(可能是 const)左值引用和通过(可能是 const)右值引用。

考虑这个函数:

template<class T>
void Fwd(T &&v) { Call(std::forward<T>(v)); }

按值(value)

如果 Call按值获取其参数,则必须在该参数中进行复制/移动。哪一个取决于传入的值是什么。如果传入的值是左值,那么它必须复制左值。如果传入的值是一个右值(它们统称为 xvalues 和 prvalues),那么它必须从它移动。

如果您调用Fwd对于左值,C++ 的类型推导规则意味着 T将推导出为 Type& , 其中 Type是左值的类型。显然,如果左值为 const ,推导出为const Type& .引用折叠规则意味着 Type & &&变成 Type &对于 v ,一个左值引用。这正是我们需要调用的 Call .用左值引用调用它会强制复制,就像我们直接调用它一样。

如果您调用Fwd带有右值(即:Type 临时表达式或某些 Type&& 表达式),然后 T将推导出为 Type .引用折叠规则给了我们Type && ,这会引发移动/复制,这几乎就像我们直接调用它一样(减去省略号)。

通过左值引用

如果 Call通过左值引用获取它的值,那么它应该只在用户使用左值参数时才可以调用。如果它是一个 const-lvalue 引用,那么它可以被任何东西(lvalue、xvalue、prvalue)调用。

如果您调用Fwd使用左值,我们再次得到 Type&作为 v 的类型.这将绑定(bind)到非常量左值引用。如果我们用 const 左值调用它,我们得到 const Type& ,它只会绑定(bind)到 Call 中的 const 左值引用参数.

如果您调用Fwd使用 xvalue,我们再次得到 Type&&作为 v 的类型.这将不允许您调用采用非常量左值的函数,因为 xvalue 不能绑定(bind)到非常量左值引用。它可以绑定(bind)到一个 const 左值引用,所以如果 Call使用了 const& ,我们可以调用Fwd有一个 xvalue。

如果您调用Fwd有了prvalue,我们再次得到Type&& ,所以一切都像以前一样工作。您不能将临时值传递给采用非常量左值的函数,因此我们的转发函数同样会在尝试这样做时窒息。

通过右值引用

如果 Call通过右值引用获取它的值,那么它应该只在用户使用 xvalue 或 rvalue 参数时才可调用。

如果您调用Fwd使用左值,我们得到 Type& .这不会绑定(bind)到右值引用参数,因此会导致编译错误。一个 const Type&也不会绑定(bind)到右值引用参数,所以它仍然失败。这正是如果我们调用 Call 会发生的事情直接用左值。

如果您调用Fwd使用 xvalue,我们得到 Type&& ,这有效(当然,cv 资格仍然很重要)。

使用纯右值也是如此。

标准::转发

std::forward 本身以类似的方式使用引用折叠规则,以便将传入的右值引用作为 xvalues(Type&& 的函数返回值是 xvalues)和传入的左值引用作为左值(返回 Type&)。

关于c++ - 简要说明引用折叠规则请求 : (1) A& & -> A& , (2) A& && -> A& , (3) A&& & -> A& , 和 (4) A&& && -> A&&,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48803587/

相关文章:

c++ - 比较 blitz++、 Armadillo 、boost::MultiArray

c++ - 在 C++11 中逐列迭代 2D 和 3D vector ?

c++ - 我如何有效地在元素之前和之后搜索关键短语

visual-studio-2010 - std::make_pair 的这种用法在 GCC 3 和 4 中工作正常。但在 Visual Studio C++ 2010 中失败。为什么?

c++ - 用数组初始化 std::string 的 vector

c++ - 动态链接库 - 构建可执行文件时成功,创建另一个 .so 时相同的设置失败

c++ - 在 C++ 中创建未初始化的 std::thread 时出现错误 C2280

c++ - 使用 c-preprocessor 自动生成函数转发器

c++ - 有或没有虚拟的子类与性能与便利性

c++ - 如何告诉编译器我的 friend 函数是函数模板