14

我遇到了一个代码,在哪里std::forward使用。我用谷歌搜索了很长时间,无法理解它的真正目的和用途。

我在stackoverflow中看到过类似的线程,但仍然不清楚。有人可以用一个简单的例子来解释吗?

PS:我已经浏览了这个页面,但仍然无法欣赏它的使用。请不要将此问题标记为重复,而是尝试帮助我。

4

4 回答 4

21

正如您链接的页面所显示的那样:

这是一个辅助函数,允许将作为右值引用的参数完美转发到推导类型,保留任何潜在的移动语义。

当您有一个命名值时,如

void f1(int& namedValue){
    ...
}

或在

void f2(int&& namedValue){
    ...
}

无论如何,它都会评估.lvalue

更进一步。假设你有一个模板函数

template <typename T>
void f(T&& namedValue){
    ...
}

可以使用左值或右值调用此类函数;但是,无论如何,namedValue的计算lvalue结果都是.

现在假设您有两个辅助函数重载

void helper(int& i){
    ...
}
void helper(int&& i){
    ...
}

helper从内部呼唤f

template <typename T>
void f(T&& namedValue){
    helper(namedValue);
}

将始终为 调用第一个重载helper,因为namedValue它是一个命名值,它自然地计算为一个lvalue.

为了在适当的时候调用第二个版本(即当f使用右值参数调用时),你写

template <typename T>
void f(T&& namedValue){
    helper( std::forward<T>(namedValue) );
}

所有这些都在以下文档中简洁地表达了

对这个函数的需求源于这样一个事实,即所有命名值(例如函数参数)总是评估为左值(即使是那些声明为右值引用的值),这给保留将参数转发给其他函数的模板函数的潜在移动语义带来了困难.

于 2013-09-04T16:34:23.733 回答
4

每个表达式恰好属于以下两个值类别之一:左值或右值。

通常,如果您调用如下函数:

template<typename T>
void f(T t);

template<typename T>
void g(T t)
{
    f(t);
}

参数的值类别g在调用 g 和 f 之间丢失,因为命名参数,如局部变量,总是左值。

通过使用std::forward并将参数调整为使用引用折叠的“通用引用”,您可以保留值类别:

template<typename T>
void f(T&& t);

template<typename T>
void g(T&& t)
{
    f(forward<T>(t));
}

这就是为什么它被称为“转发”,因为你正在“转发”价值类别,而不是失去它。

因此,在示例中,如果您g使用右值调用,则 f 将使用右值而不是左值调用。

于 2013-09-04T16:23:59.863 回答
1

它用于在将参数传递给另一个函数时保留模板中参数的确切类型。例如:

template<class T>
void wrapper(T&& arg)
{
    foo(std::forward<T>(arg)); // Forward a single argument.
}

这工作如下:

  • 如果函数wrapper得到 astd::stringconst std::string&,则foo调用时就好像arg其类型为const std::string&

  • 如果函数wrapper得到 a std::string&,则foo调用时就好像arg其类型为std::string&

  • 如果函数wrapper得到 a std::string&&,则foo调用时就好像arg其类型为std::string&&

解决的问题std::forward 是,根据通常的规则,arg函数内部的类型是std::string即使我们传递std::string&&wrapper. std::forward允许将的实际类型(无论是、或, )注入调用站点。TTT&const T&T&&

于 2013-09-04T16:25:29.293 回答
0

它的基本用途是你在g被这样调用的函数中:

g(T1 p1, T2 p2, /* ... */);

并且您想调用f具有完全相同类型的函数:

f(T1 p1, T2 p2, /* ... */);
于 2013-09-04T16:30:36.953 回答