发布于 2014-07-14 09:46:39
纯英语尝试
这个问题可能太复杂,无法用简单的英语句子准确地描述,但人们可以认为完美转发是一种将传递到另一个函数的临时值转移到另一个函数的方法,就好像第一个函数根本不存在一样,因此没有任何不必要的副本或作业。C++11允许您通过在r值(&&)和l-value (&)引用之间引入一些转换规则来做到这一点,当您试图从中获取引用(r值或l值)时。
R-值引用是C++11的一个特性,它们被设计用于地址移动语义和完善的转发问题()。
这是通俗易懂的解释,但如果你想彻底理解这个问题,我建议你阅读以下内容:
问题是:
我们希望将传递给函数F
的一些临时值传递给另一个E
,而不需要任何复制或赋值。
试图解决这个问题
const
会延长堆栈上临时引用的生存期(这是历史上为避免常见的悬空引用错误而做的),因此,以下工作如下
模板空洞E(const T& a) {}模板空洞F(const T& a) { E(a);}
但缺点是,您必须修改函数的签名以符合此解决方案C++11中的解决方案
C++11定义了一些状态的规则
“给定类型TR是对类型T的引用,尝试创建类型”lvalue引用cv TR“将创建类型”lvalue引用T“,而尝试创建类型”rvalue引用cv TR“则会创建类型TR。”
在人类形态中(TR =对T类型的引用,R=引用):
TR R
T& & -> T& // an lvalue reference to cv TR (becomes)-> lvalue reference to T
T& && -> T& // an rvalue reference to cv TR (becomes)-> TR (lvalue reference to T)
T&& & -> T& // an lvalue reference to cv TR (becomes)-> lvalue reference to T
T&& && -> T&& // an rvalue reference to cv TR (becomes)-> TR (rvalue reference to T)
这里最重要的优点是,现在可以跟踪接收到的函数的类型:您可以接收一个l-值并将相同的l-值传递给E,或者您可以接收一个r值并将相同的r值传递给E(在转换它之后,因为对任何类型引用的l-值引用变成了l-值引用):
template<typename T> void E(T&& a) {}
template<typename T> void F(T&& a) { E(static_cast<T&&>(a)); }
一种句法糖
static_cast<T&&>(a)
是
std::forward<T>(a); // is the same as static_cast<T&&>(a);
因此,解决问题并使您的生活更轻松的最终代码是
template<typename T> void E(T&& a) {}
template<typename T> void F(T&& a) { E(std::forward<T>(a)); }
实例化
参考资料:赫伯萨特的博客和其他一些来源,不幸的是,我找不到了。如果有人有线索,请写在下面的评论,我会更新这篇文章。谢谢。
发布于 2014-07-14 09:27:04
处理r值引用和基准塌陷可能比最初看上去更加复杂。
完美转发
完美转发是为了确保提供给函数的参数被转发(传递)到与原提供相同的值类别(基本上是r值对l值)的另一个函数。
它通常与可能发生引用折叠的模板函数一起使用。
它也可以是在同一功能中使用。
Scott在他的2013年土生土长的介绍中给出了下面的伪代码来解释std::forward
的工作原理(大约在20分钟内);
template <typename T>
T&& forward(T&& param) { // T&& here is formulated to disallow type deduction
if (is_lvalue_reference<T>::value) {
return param; // return type T&& collapses to T& in this case
}
else {
return move(param);
}
}
示例
上面的一个例子,一个典型的例子是make_unique
template<class T, class... U>
std::unique_ptr<T> make_unique(U&&... u)
{
return std::unique_ptr<T>(new T(std::forward<U>(u)...));
}
在示例中,unique_ptr
的参数通过make_unique
提供给它,就好像它们是直接提供给unique_ptr
的一样,即保持参数的引用、l值和r值性质。
一个更具体的例子;
#include <iostream>
#include <utility>
#include <memory>
struct A {
// implementation excluded
};
struct B {
B(A &) // ctor 1
{
std::cout << "ctor 1" << std::endl;
}
B(A&&) // ctor 2
{
std::cout << "ctor 2" << std::endl;
}
};
int main()
{
A a;
auto b1 = std::make_unique<B>(a); // ctor 1 is used
auto b2 = std::make_unique<B>(A()); // ctor 2 is used
}
简略的
完美的转发依赖于一些C++11新的基本语言结构,这些构造构成了我们现在在泛型编程中看到的大部分内容的基础:
std::forward
的使用目前在公式化的std::forward<T>
中,了解std::forward
的工作原理有助于理解为什么会这样,还有助于识别rvalue的非惯用或错误使用、引用崩溃等。
Thomas在完美的转发问题和解决方案上提供了一个漂亮但密集的写下来。
https://stackoverflow.com/questions/24732926
复制相似问题