本文介绍了使用std :: forward的主要目的是什么,它可以解决哪些问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在完美转发中, std :: forward 用于转换命名的右值引用 t1 t2 到未命名的右值引用。这样做的目的是什么?如果我们离开 t1 & ;,这将如何影响调用函数 inner t2 作为左值?

In perfect forwarding, std::forward is used to convert the named rvalue references t1 and t2 to unnamed rvalue references. What is the purpose of doing that? How would that affect the called function inner if we leave t1 & t2 as lvalues?

template <typename T1, typename T2>
void outer(T1&& t1, T2&& t2)
{
    inner(std::forward<T1>(t1), std::forward<T2>(t2));
}


推荐答案

您必须了解转发问题。您可以因此,我们必须找到另一种方法。

In C++11, we get a chance to fix this. One solution modifies template deduction rules on existing types, but this potentially breaks a great deal of code. So we have to find another way.

解决方案是改为使用新添加的 rvalue-references ;我们可以在推导右值引用类型并创建任何所需结果时引入新规则。毕竟,我们现在不可能破译代码。

The solution is to instead use the newly added rvalue-references; we can introduce new rules when deducing rvalue-reference types and create any desired result. After all, we cannot possibly break code now.

如果给出了对引用的引用(请注意引用是一个包含性术语,表示两个 T& T& ),我们使用以下规则找出结果类型:

If given a reference to a reference (note reference is an encompassing term meaning both T& and T&&), we use the following rule to figure out the resulting type:

或以表格形式:

TR   R

T&   &  -> T&  // lvalue reference to cv TR -> lvalue reference to T
T&   && -> T&  // rvalue reference to cv TR -> TR (lvalue reference to T)
T&&  &  -> T&  // lvalue reference to cv TR -> lvalue reference to T
T&&  && -> T&& // rvalue reference to cv TR -> TR (rvalue reference to T)

接下来,使用模板自变量推导:如果自变量是左值A ,我们为模板参数提供一个对A的左值引用。否则,我们可以正常推断。这给出了所谓的通用参考文献(术语现在是正式参考)。

Next, with template argument deduction: if an argument is an lvalue A, we supply the template argument with an lvalue reference to A. Otherwise, we deduce normally. This gives so-called universal references (the term forwarding reference is now the official one).

这为什么有用?因为结合起来,我们可以保持跟踪类型的值类别的能力:如果是左值,则有一个左值引用参数,否则就有一个右值引用参数。

Why is this useful? Because combined we maintain the ability to keep track of the value category of a type: if it was an lvalue, we have an lvalue-reference parameter, otherwise we have an rvalue-reference parameter.

在代码中:

template <typename T>
void deduce(T&& x);

int i;
deduce(i); // deduce<int&>(int& &&) -> deduce<int&>(int&)
deduce(1); // deduce<int>(int&&)

最后一件事是转发变量的值类别。请记住,一旦在函数内部,该参数就可以作为左值传递给任何东西:

The last thing is to "forward" the value category of the variable. Keep in mind, once inside the function the parameter could be passed as an lvalue to anything:

void foo(int&);

template <typename T>
void deduce(T&& x)
{
    foo(x); // fine, foo can refer to x
}

deduce(1); // okay, foo operates on x which has a value of 1

E需要获得与我们得到的相同的价值类别!解决方案是这样的:

That's no good. E needs to get the same kind of value-category that we got! The solution is this:

static_cast<T&&>(x);

这是做什么的?假设我们位于 ducuce 函数中,并且已经传递了一个左值。这意味着 T A& ,因此静态类型转换的目标类型是 A& && ,或仅 A& 。由于 x 已经是 A& ,因此我们什么也不做,只剩下一个左值引用。

What does this do? Consider we're inside the deduce function, and we've been passed an lvalue. This means T is a A&, and so the target type for the static cast is A& &&, or just A&. Since x is already an A&, we do nothing and are left with an lvalue reference.

传递右值后, T A ,因此静态类型转换的目标类型为 A& 。强制转换会产生右值表达式,该表达式不能再传递给左值引用。我们保持了参数的值类别。

When we've been passed an rvalue, T is A, so the target type for the static cast is A&&. The cast results in an rvalue expression, which can no longer be passed to an lvalue reference. We've maintained the value category of the parameter.

将它们放在一起可以使我们完美转发:

Putting these together gives us "perfect forwarding":

template <typename A>
void f(A&& a)
{
    E(static_cast<A&&>(a));
}

f 收到时一个左值, E 得到一个左值。当 f 收到右值时, E 得到右值。完美。

When f receives an lvalue, E gets an lvalue. When f receives an rvalue, E gets an rvalue. Perfect.

当然,我们希望摆脱丑陋的状况。 static_cast< T&> 神秘而又难以记住;让我们改为创建一个名为 forward 的实用程序函数,该函数执行相同的操作:

And of course, we want to get rid of the ugly. static_cast<T&&> is cryptic and weird to remember; let's instead make a utility function called forward, which does the same thing:

std::forward<A>(a);
// is the same as
static_cast<A&&>(a);

这篇关于使用std :: forward的主要目的是什么,它可以解决哪些问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-06 00:32