10

据我所知,在 C++11 中,通用引用应始终与 一起使用std::forward,但我不确定如果std::forward不使用会出现什么样的问题。

template <T>
void f(T&& x);
{
    // What if x is used without std::forward<T>(x) ?
}

您能否提供一些在这种情况下可能出现的问题的说明?

4

4 回答 4

16

没有这样的规则总是std::forward通用引用一起使用。相反,在具有通用引用std::forward的函数中到处使用可能是危险的。看看下面的例子:

template <typename T>
auto make_pair(T&& t)
{
    return std::make_tuple(std::forward<T>(t), std::forward<T>(t)); // BAD
}

如果你用 调用这个函数make_pair(std::string{"foobar"}),结果是反直觉的,因为你从同一个对象移动了两次。


更新:这是另一个示例,说明在没有完美转发的情况下使用通用引用确实很有意义:

template <typename Range, typename Action>
void foreach(Range&& range, Action&& action)
{
    using std::begin;
    using std::end;
    for (auto p = begin(range), q = end(range); p != q; ++p) {
        action(*p);
    }
}
  • range是一个通用引用很好,这样调用者就可以将foreach与一个临时容器和一个动作一起使用,即在元素上调用一个非常量成员函数。
  • action是一个通用引用很好,这样调用者就可以将可变的 lambda 表达式作为 action 传递。
  • 使用std::forwardfor range或 for action是错误的。
于 2014-04-25T07:12:11.260 回答
10

假设是这样f调用的:

f(someType{});

如果身体fx

foo(x);

并且有两个重载foo

void foo(someType const&);

void foo(someType&&);

不使用std::forward,作为x左值,调用以下重载

void foo(someType const&);

这可能会花费您潜在的优化。

使用

foo(std::forward<T>(x));

确保选择了正确的过载foo

于 2014-04-25T06:56:59.850 回答
6

有名字的东西是左值。这意味着在函数体中,t是一个左值。通用引用最终是左值引用还是右值引用并不重要。如果它被命名,它是一个左值。

如果您因此直接传递该参数,您将传递一个左值。

在您只想将不透明参数传递给另一个函数的情况下,您希望完全按原样传递它。如果它是一个左值,你想把它作为一个左值传递;如果它是一个右值,你想传递一个右值。如前所述,直接传递它总是作为左值传递。forward是否需要将其作为正确的值传递,

从性能角度来看,总是传递左值的代码可能会受到影响,但我想说,在考虑这个特定问题时,您可以忽略这一点。不总是传递左值有一个更紧迫的问题:虽然复制某些类型可能很昂贵,但某些其他类型根本无法复制,例如std::unique_ptr. 对于那些在转发时保留右值的类型不是性能问题,而是让您的代码甚至可以编译。

于 2014-04-25T09:57:24.123 回答
0

您不应多次转发变量。

于 2014-04-25T12:40:48.253 回答