为什么要使用一个完全转发的值(一个函子)?

时间:2022-11-25 18:59:31

C++11 (and C++14) introduces additional language constructs and improvements that target generic programming. These include features such as;

c++ 11(和c++ 14)引入了针对通用编程的其他语言构造和改进。这些特征包括:

  • R-value references
  • 热阻的引用
  • Reference collapsing
  • 参考崩溃
  • Perfect forwarding
  • 完美的转发
  • Move semantics, variadic templates and more
  • 移动语义、可变模板等等

I was browsing an earlier draft of the C++14 specification (now with updated text) and the code in an example in §20.5.1, Compile-time integer sequences, that I found interesting and peculiar.

我之前浏览一个c++ 14规范的草案(现在更新文本)和一个示例中的代码在§20.5.1,编译时整数序列,我发现有趣和独特的。

template<class F, class Tuple, std::size_t... I>
decltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence<I...>) {
  return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}

template<class F, class Tuple>
decltype(auto) apply(F&& f, Tuple&& t) {
  using Indices = make_index_sequence<std::tuple_size<Tuple>::value>;
  return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices());
}

Online here [intseq.general]/2.

在线(intseq.general)/ 2。

Question

问题

  • Why was the function f in apply_impl being forwarded, i.e. why std::forward<F>(f)(std::get...?
  • 为什么apply_impl中的函数f被转发,即为什么std: forward< f >(f)(std::get…)?
  • Why not just apply the function as f(std::get...?
  • 为什么不直接应用函数f(std::get…?)

2 个解决方案

#1


45  

In Brief...

The TL;DR, you want to preserve the value category (r-value/l-value nature) of the functor because this can affect the overload resolution, in particular the ref-qualified members.

TL;DR,您想要保存函数的值类别(r值/l值性质),因为这会影响到重载解析,特别是对ref限定的成员。

Function definition reduction

To focus on the issue of the function being forwarded, I've reduced the sample (and made it compile with a C++11 compiler) to;

为了关注正在转发的函数的问题,我将示例(并让它使用c++ 11编译器进行编译)简化为;

template<class F, class... Args>
auto apply_impl(F&& func, Args&&... args) -> decltype(std::forward<F>(func)(std::forward<Args>(args)...)) {
  return std::forward<F>(func)(std::forward<Args>(args)...);
}

And we create a second form, where we replace the std::forward(func) with just func;

我们创建了第二个表单,用func替换std: forward(func);

template<class F, class... Args>
auto apply_impl_2(F&& func, Args&&... args) -> decltype(func(std::forward<Args>(args)...)) {
  return func(std::forward<Args>(args)...);
}

Sample evaluation

Evaluating some empirical evidence of how this behaves (with conforming compilers) is a neat starting point for evaluating why the code example was written as such. Hence, in addition we will define a general functor;

评估一些经验证据(使用符合标准的编译器)是评估为什么编写代码示例的一个很好的起点。因此,我们将定义一个一般的函子;

struct Functor1 {
  int operator()(int id) const
  {
    std::cout << "Functor1 ... " << id << std::endl;
    return id;
  }
};

Initial sample

最初的样本

Run some sample code;

运行一些示例代码;

int main()
{
  Functor1 func1;
  apply_impl_2(func1, 1);
  apply_impl_2(Functor1(), 2);
  apply_impl(func1, 3);
  apply_impl(Functor1(), 4);
}

And the output is as expected, independent of whether an r-value is used Functor1() or an l-value func when making the call to apply_impl and apply_impl_2 the overloaded call operator is called. It is called for both r-values and l-values. Under C++03, this was all you got, you could not overload member methods based on the "r-value-ness" or "l-value-ness" of the object.

输出如预期的那样,独立于调用apply_impl和apply_imp_2时是否使用了一个r值Functor1()或一个l-value func。它同时需要r值和l值。在c++ 03下,这就是您所得到的全部,您不能基于对象的“r-值性”或“l-值性”重载成员方法。

Functor1 ... 1
Functor1 ... 2
Functor1 ... 3
Functor1 ... 4

Functor1……1 Functor1…2 Functor1…3 Functor1…4

Ref-qualified samples

Ref-qualified样品

We now need to overload that call operator to stretch this a little further...

我们现在需要重载调用操作符来进一步扩展…

struct Functor2 {
  int operator()(int id) const &
  {
    std::cout << "Functor2 &... " << id << std::endl;
    return id;
  }
  int operator()(int id) &&
  {
    std::cout << "Functor2 &&... " << id << std::endl;
    return id;
  }
};

We run another sample set;

我们运行另一个样本集;

int main()
{
  Functor2 func2;
  apply_impl_2(func2, 5);
  apply_impl_2(Functor2(), 6);
  apply_impl(func2, 7);
  apply_impl(Functor2(), 8);
}

And the output is;

和输出;

Functor2 &... 5
Functor2 &... 6
Functor2 &... 7
Functor2 &&... 8

Functor2 &……5 Functor2 &……6 Functor2 &……7 Functor2 & &……8

Discussion

讨论

In the case of apply_impl_2 (id 5 and 6), the output is not as may have been initially been expected. In both cases, the l-value qualified operator() is called (the r-value is not called at all). It may have been expected that since Functor2(), an r-value, is used to call apply_impl_2 the r-value qualified operator() would have been called. The func, as a named parameter to apply_impl_2, is an r-value reference, but since it is named, it is itself an l-value. Hence the l-value qualified operator()(int) const& is called in both the case of the l-value func2 being the argument and the r-value Functor2() being used as the argument.

在apply_imp_2 (id 5和6)的情况下,输出并不像最初预期的那样。在这两种情况下,都调用了l值限定运算符()(不调用r值)。由于函数2()是一个r值,它被用来调用apply_impl_2,所以应该调用r-value限定操作符()。func作为apply_impl_2的命名参数,是一个r值引用,但由于它已命名,所以它本身是一个l值。因此,l-value限定操作符()(int) const&在以l-value func2为参数和以r-value Functor2()为参数的情况下都被调用。

In the case of apply_impl (id 7 and 8) the std::forward<F>(func) maintains or preserves the r-value/l-value nature of the argument provided for func. Hence the l-value qualified operator()(int) const& is called with the l-value func2 used as the argument and the r-value qualified operator()(int)&& when the r-value Functor2() is used as the argument. This behaviour is what would have been expected.

在apply_impl (id 7和8)中,std::forward (func)维护或保留为func提供的参数的r值/l值性质。因此,调用l-value限定操作符()(int) const&时使用l-value func2作为参数,当使用r-value Functor2()作为参数时,调用r-value限定操作符()&。这种行为是预料之中的。

Conclusions

The use of std::forward, via perfect forwarding, ensures that we preserve the r-value/l-value nature of the original argument for func. It preserves their value category.

std::forward,通过完美转发,确保我们保留了func原始参数的r-value/l-value性质。它保留了它们的价值类别。

It is required, std::forward can and should be used for more than just forwarding arguments to functions, but also when the use of an argument is required where the r-value/l-value nature must be preserved. Note; there are situations where the r-value/l-value cannot or should not be preserved, in these situations std::forward should not be used (see the converse below).

它是必需的,std::forward不仅可以而且应该用于将参数转发到函数中,还应该用于必须保留r-value/l-value性质的参数的使用。请注意;有些情况下,r值/l值不能或不应该被保留,在这些情况下std:::forward不应该被使用(见下面的相反情况)。

There are many examples popping up that inadvertently lose the r-value/l-value nature of the arguments via a seemingly innocent use of an r-value reference.

出现了许多例子,这些例子无意中失去了参数的r-value/l-value属性,因为它们似乎是无辜地使用了r-value引用。

It has always been hard to write well defined and sound generic code. With the introduction of r-value references, and reference collapsing in particular, it has become possible to write better generic code, more concisely, but we need to be ever more aware of what the original nature of the arguments provided are and make sure that they are maintained when we use them in the generic code we write.

一直以来,很难编写定义良好、可靠的通用代码。通过引入热阻引用和参考特别是崩溃,它已成为可能更好地编写通用代码,更简洁,但我们需要更多了解的原始特性参数提供维护和确保他们当我们在我们编写通用代码中使用它们。

Full sample code can be found here

完整的示例代码可以在这里找到

Corollary and converse

  • A corollary of the question would be; given reference collapsing in a templated function, how is the r-value/l-value nature of the argument maintained? The answer - use std::forward<T>(t).
  • 这个问题的推论是;给定模板函数中崩溃的引用,参数的r-值/l-值性质是如何维护的?答案-使用std::forward (T)
  • Converse; does std::forward solve all your "universal reference" problems? No it doesn't, there are cases where it should not be used, such as forwarding the value more than once.
  • 交谈;std:向前解决你所有的“通用参考”问题吗?不,它不是,有些情况下不应该使用它,比如多次转发值。

Brief background to perfect forwarding

Perfect forwarding may be unfamiliar to some, so what is perfect forwarding?

完美转发对有些人来说可能是陌生的,那么什么是完美转发呢?

In brief, perfect forwarding is there to ensure that the argument provided to a function is forwarded (passed) to another function with the same value category (basically r-value vs. l-value) as originally provided. It is typically used with template functions where reference collapsing may have taken place.

简而言之,完美转发的存在是为了确保向函数提供的参数被转发(传递)给具有相同值类别(基本上是r-value vs. l-value)的另一个函数。它通常与引用崩溃可能发生的模板函数一起使用。

Scott Meyers gives the following pseudo code in his Going Native 2013 presentation to explain the workings of std::forward (at approximately the 20 minute mark);

Scott Meyers在他的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);
  }
}

Perfect forwarding depends on a handful of fundamental language constructs new to C++11 that form the bases for much of what we now see in generic programming:

完美的转发依赖于一些基本的语言结构,这些结构是c++ 11的新结构,它们构成了我们现在在泛型编程中看到的很多东西的基础:

  • Reference collapsing
  • 参考崩溃
  • Rvalue references
  • 右值引用
  • Move semantics
  • 移动语义

The use of std::forward is currently intended in the formulaic std::forward<T>, understanding how std::forward works helps understand why this is such, and also aids in identifying non-idiomatic or incorrect use of rvalues, reference collapsing and ilk.

std::forward的使用目前在公式化的std:::forward 中,理解std:::forward的工作有助于理解为什么会这样,也有助于识别非惯用或错误地使用rvalue、引用崩溃和ilk。

Thomas Becker provides a nice, but dense write up on the perfect forwarding problem and solution.

托马斯·贝克尔提供了一个很好的,但密集的关于完美的转发问题和解决方案的描述。

What are ref-qualifiers?

The ref-qualifiers (lvalue ref-qualifier & and rvalue ref-qualifier &&) are similar to the cv-qualifiers in that they (the ref-qualified members) are used during overload resolution to determine which method to call. They behave as you would expect them to; the & applies to lvalues and && to rvalues. Note: Unlike cv-qualification, *this remains an l-value expression.

ref-qualifier (lvalue ref-qualifier &和rvalue ref-qualifier &&)类似于cv-qualifier,它们(ref-qualified成员)在重载解析中使用,以决定调用哪个方法。他们的行为和你期望的一样;该&适用于lvalues和&& rvalues。注意:与cv限定值不同,*这仍然是一个l-value表达式。

#2


12  

Here is a practical example.

这里有一个实际的例子。

struct concat {
  std::vector<int> state;
  std::vector<int> const& operator()(int x)&{
    state.push_back(x);
    return state;
  }
  std::vector<int> operator()(int x)&&{
    state.push_back(x);
    return std::move(state);
  }
  std::vector<int> const& operator()()&{ return state; }
  std::vector<int> operator()()&&{ return std::move(state); }
};

This function object takes an x, and concatenates it to an internal std::vector. It then returns that std::vector.

这个函数对象接受一个x,并将它连接到一个内部std::vector。然后返回std::vector。

If evaluated in an rvalue context it moves to a temporary, otherwise it returns a const& to the internal vector.

如果在一个rvalue上下文中求值,它将移动到一个临时的,否则它将返回一个const&到内部向量。

Now we call apply:

现在我们所说的应用:

auto result = apply( concat{}, std::make_tuple(2) );

because we carefully forwarded our function object, only 1 std::vector buffer is allocated. It is simply moved out to result.

因为我们仔细地转发了函数对象,所以只分配了一个std::vector buffer。它被简单地移出结果。

Without the careful forwarding, we end up creating an internal std::vector, and we copy it to result, then discard the internal std::vector.

没有仔细的转发,我们最终创建了一个内部std::vector,我们将它复制到result,然后丢弃内部std:::vector。

Because the operator()&& knows that the function object should be treated as a rvalue about to be destroyed, it can rip the guts out of the function object while doing its operation. The operator()& cannot do this.

因为操作符()&&知道函数对象应该被当作一个将要被销毁的rvalue,它可以在执行操作时从函数对象中取出内脏。操作符()&不能这样做。

Careful use of perfect forwarding of function objects enables this optimization.

仔细使用功能对象的完美转发可以实现此优化。

Note, however, that there is very little use of this technique "in the wild" at this point. Rvalue qualified overloading is obscure, and doing so to operator() moreso.

然而,请注意,在这一点上,这种技术“在野外”很少使用。Rvalue限定重载是模糊的,这样做是为了操作()moreso。

I could easily see future versions of C++ automatically using the rvalue state of a lambda to implicitly move its captured-by-value data in certain contexts, however.

我可以很容易地看到将来的c++版本使用lambda的rvalue状态自动地在某些上下文中隐式地移动其按值捕获的数据。

#1


45  

In Brief...

The TL;DR, you want to preserve the value category (r-value/l-value nature) of the functor because this can affect the overload resolution, in particular the ref-qualified members.

TL;DR,您想要保存函数的值类别(r值/l值性质),因为这会影响到重载解析,特别是对ref限定的成员。

Function definition reduction

To focus on the issue of the function being forwarded, I've reduced the sample (and made it compile with a C++11 compiler) to;

为了关注正在转发的函数的问题,我将示例(并让它使用c++ 11编译器进行编译)简化为;

template<class F, class... Args>
auto apply_impl(F&& func, Args&&... args) -> decltype(std::forward<F>(func)(std::forward<Args>(args)...)) {
  return std::forward<F>(func)(std::forward<Args>(args)...);
}

And we create a second form, where we replace the std::forward(func) with just func;

我们创建了第二个表单,用func替换std: forward(func);

template<class F, class... Args>
auto apply_impl_2(F&& func, Args&&... args) -> decltype(func(std::forward<Args>(args)...)) {
  return func(std::forward<Args>(args)...);
}

Sample evaluation

Evaluating some empirical evidence of how this behaves (with conforming compilers) is a neat starting point for evaluating why the code example was written as such. Hence, in addition we will define a general functor;

评估一些经验证据(使用符合标准的编译器)是评估为什么编写代码示例的一个很好的起点。因此,我们将定义一个一般的函子;

struct Functor1 {
  int operator()(int id) const
  {
    std::cout << "Functor1 ... " << id << std::endl;
    return id;
  }
};

Initial sample

最初的样本

Run some sample code;

运行一些示例代码;

int main()
{
  Functor1 func1;
  apply_impl_2(func1, 1);
  apply_impl_2(Functor1(), 2);
  apply_impl(func1, 3);
  apply_impl(Functor1(), 4);
}

And the output is as expected, independent of whether an r-value is used Functor1() or an l-value func when making the call to apply_impl and apply_impl_2 the overloaded call operator is called. It is called for both r-values and l-values. Under C++03, this was all you got, you could not overload member methods based on the "r-value-ness" or "l-value-ness" of the object.

输出如预期的那样,独立于调用apply_impl和apply_imp_2时是否使用了一个r值Functor1()或一个l-value func。它同时需要r值和l值。在c++ 03下,这就是您所得到的全部,您不能基于对象的“r-值性”或“l-值性”重载成员方法。

Functor1 ... 1
Functor1 ... 2
Functor1 ... 3
Functor1 ... 4

Functor1……1 Functor1…2 Functor1…3 Functor1…4

Ref-qualified samples

Ref-qualified样品

We now need to overload that call operator to stretch this a little further...

我们现在需要重载调用操作符来进一步扩展…

struct Functor2 {
  int operator()(int id) const &
  {
    std::cout << "Functor2 &... " << id << std::endl;
    return id;
  }
  int operator()(int id) &&
  {
    std::cout << "Functor2 &&... " << id << std::endl;
    return id;
  }
};

We run another sample set;

我们运行另一个样本集;

int main()
{
  Functor2 func2;
  apply_impl_2(func2, 5);
  apply_impl_2(Functor2(), 6);
  apply_impl(func2, 7);
  apply_impl(Functor2(), 8);
}

And the output is;

和输出;

Functor2 &... 5
Functor2 &... 6
Functor2 &... 7
Functor2 &&... 8

Functor2 &……5 Functor2 &……6 Functor2 &……7 Functor2 & &……8

Discussion

讨论

In the case of apply_impl_2 (id 5 and 6), the output is not as may have been initially been expected. In both cases, the l-value qualified operator() is called (the r-value is not called at all). It may have been expected that since Functor2(), an r-value, is used to call apply_impl_2 the r-value qualified operator() would have been called. The func, as a named parameter to apply_impl_2, is an r-value reference, but since it is named, it is itself an l-value. Hence the l-value qualified operator()(int) const& is called in both the case of the l-value func2 being the argument and the r-value Functor2() being used as the argument.

在apply_imp_2 (id 5和6)的情况下,输出并不像最初预期的那样。在这两种情况下,都调用了l值限定运算符()(不调用r值)。由于函数2()是一个r值,它被用来调用apply_impl_2,所以应该调用r-value限定操作符()。func作为apply_impl_2的命名参数,是一个r值引用,但由于它已命名,所以它本身是一个l值。因此,l-value限定操作符()(int) const&在以l-value func2为参数和以r-value Functor2()为参数的情况下都被调用。

In the case of apply_impl (id 7 and 8) the std::forward<F>(func) maintains or preserves the r-value/l-value nature of the argument provided for func. Hence the l-value qualified operator()(int) const& is called with the l-value func2 used as the argument and the r-value qualified operator()(int)&& when the r-value Functor2() is used as the argument. This behaviour is what would have been expected.

在apply_impl (id 7和8)中,std::forward (func)维护或保留为func提供的参数的r值/l值性质。因此,调用l-value限定操作符()(int) const&时使用l-value func2作为参数,当使用r-value Functor2()作为参数时,调用r-value限定操作符()&。这种行为是预料之中的。

Conclusions

The use of std::forward, via perfect forwarding, ensures that we preserve the r-value/l-value nature of the original argument for func. It preserves their value category.

std::forward,通过完美转发,确保我们保留了func原始参数的r-value/l-value性质。它保留了它们的价值类别。

It is required, std::forward can and should be used for more than just forwarding arguments to functions, but also when the use of an argument is required where the r-value/l-value nature must be preserved. Note; there are situations where the r-value/l-value cannot or should not be preserved, in these situations std::forward should not be used (see the converse below).

它是必需的,std::forward不仅可以而且应该用于将参数转发到函数中,还应该用于必须保留r-value/l-value性质的参数的使用。请注意;有些情况下,r值/l值不能或不应该被保留,在这些情况下std:::forward不应该被使用(见下面的相反情况)。

There are many examples popping up that inadvertently lose the r-value/l-value nature of the arguments via a seemingly innocent use of an r-value reference.

出现了许多例子,这些例子无意中失去了参数的r-value/l-value属性,因为它们似乎是无辜地使用了r-value引用。

It has always been hard to write well defined and sound generic code. With the introduction of r-value references, and reference collapsing in particular, it has become possible to write better generic code, more concisely, but we need to be ever more aware of what the original nature of the arguments provided are and make sure that they are maintained when we use them in the generic code we write.

一直以来,很难编写定义良好、可靠的通用代码。通过引入热阻引用和参考特别是崩溃,它已成为可能更好地编写通用代码,更简洁,但我们需要更多了解的原始特性参数提供维护和确保他们当我们在我们编写通用代码中使用它们。

Full sample code can be found here

完整的示例代码可以在这里找到

Corollary and converse

  • A corollary of the question would be; given reference collapsing in a templated function, how is the r-value/l-value nature of the argument maintained? The answer - use std::forward<T>(t).
  • 这个问题的推论是;给定模板函数中崩溃的引用,参数的r-值/l-值性质是如何维护的?答案-使用std::forward (T)
  • Converse; does std::forward solve all your "universal reference" problems? No it doesn't, there are cases where it should not be used, such as forwarding the value more than once.
  • 交谈;std:向前解决你所有的“通用参考”问题吗?不,它不是,有些情况下不应该使用它,比如多次转发值。

Brief background to perfect forwarding

Perfect forwarding may be unfamiliar to some, so what is perfect forwarding?

完美转发对有些人来说可能是陌生的,那么什么是完美转发呢?

In brief, perfect forwarding is there to ensure that the argument provided to a function is forwarded (passed) to another function with the same value category (basically r-value vs. l-value) as originally provided. It is typically used with template functions where reference collapsing may have taken place.

简而言之,完美转发的存在是为了确保向函数提供的参数被转发(传递)给具有相同值类别(基本上是r-value vs. l-value)的另一个函数。它通常与引用崩溃可能发生的模板函数一起使用。

Scott Meyers gives the following pseudo code in his Going Native 2013 presentation to explain the workings of std::forward (at approximately the 20 minute mark);

Scott Meyers在他的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);
  }
}

Perfect forwarding depends on a handful of fundamental language constructs new to C++11 that form the bases for much of what we now see in generic programming:

完美的转发依赖于一些基本的语言结构,这些结构是c++ 11的新结构,它们构成了我们现在在泛型编程中看到的很多东西的基础:

  • Reference collapsing
  • 参考崩溃
  • Rvalue references
  • 右值引用
  • Move semantics
  • 移动语义

The use of std::forward is currently intended in the formulaic std::forward<T>, understanding how std::forward works helps understand why this is such, and also aids in identifying non-idiomatic or incorrect use of rvalues, reference collapsing and ilk.

std::forward的使用目前在公式化的std:::forward 中,理解std:::forward的工作有助于理解为什么会这样,也有助于识别非惯用或错误地使用rvalue、引用崩溃和ilk。

Thomas Becker provides a nice, but dense write up on the perfect forwarding problem and solution.

托马斯·贝克尔提供了一个很好的,但密集的关于完美的转发问题和解决方案的描述。

What are ref-qualifiers?

The ref-qualifiers (lvalue ref-qualifier & and rvalue ref-qualifier &&) are similar to the cv-qualifiers in that they (the ref-qualified members) are used during overload resolution to determine which method to call. They behave as you would expect them to; the & applies to lvalues and && to rvalues. Note: Unlike cv-qualification, *this remains an l-value expression.

ref-qualifier (lvalue ref-qualifier &和rvalue ref-qualifier &&)类似于cv-qualifier,它们(ref-qualified成员)在重载解析中使用,以决定调用哪个方法。他们的行为和你期望的一样;该&适用于lvalues和&& rvalues。注意:与cv限定值不同,*这仍然是一个l-value表达式。

#2


12  

Here is a practical example.

这里有一个实际的例子。

struct concat {
  std::vector<int> state;
  std::vector<int> const& operator()(int x)&{
    state.push_back(x);
    return state;
  }
  std::vector<int> operator()(int x)&&{
    state.push_back(x);
    return std::move(state);
  }
  std::vector<int> const& operator()()&{ return state; }
  std::vector<int> operator()()&&{ return std::move(state); }
};

This function object takes an x, and concatenates it to an internal std::vector. It then returns that std::vector.

这个函数对象接受一个x,并将它连接到一个内部std::vector。然后返回std::vector。

If evaluated in an rvalue context it moves to a temporary, otherwise it returns a const& to the internal vector.

如果在一个rvalue上下文中求值,它将移动到一个临时的,否则它将返回一个const&到内部向量。

Now we call apply:

现在我们所说的应用:

auto result = apply( concat{}, std::make_tuple(2) );

because we carefully forwarded our function object, only 1 std::vector buffer is allocated. It is simply moved out to result.

因为我们仔细地转发了函数对象,所以只分配了一个std::vector buffer。它被简单地移出结果。

Without the careful forwarding, we end up creating an internal std::vector, and we copy it to result, then discard the internal std::vector.

没有仔细的转发,我们最终创建了一个内部std::vector,我们将它复制到result,然后丢弃内部std:::vector。

Because the operator()&& knows that the function object should be treated as a rvalue about to be destroyed, it can rip the guts out of the function object while doing its operation. The operator()& cannot do this.

因为操作符()&&知道函数对象应该被当作一个将要被销毁的rvalue,它可以在执行操作时从函数对象中取出内脏。操作符()&不能这样做。

Careful use of perfect forwarding of function objects enables this optimization.

仔细使用功能对象的完美转发可以实现此优化。

Note, however, that there is very little use of this technique "in the wild" at this point. Rvalue qualified overloading is obscure, and doing so to operator() moreso.

然而,请注意,在这一点上,这种技术“在野外”很少使用。Rvalue限定重载是模糊的,这样做是为了操作()moreso。

I could easily see future versions of C++ automatically using the rvalue state of a lambda to implicitly move its captured-by-value data in certain contexts, however.

我可以很容易地看到将来的c++版本使用lambda的rvalue状态自动地在某些上下文中隐式地移动其按值捕获的数据。