什么样的问题不转发普遍参考?

时间:2014-04-25 06:54:05

标签: c++ c++11 perfect-forwarding universal-reference

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

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

您能举例说明在这种情况下可能出现的问题吗?

4 个答案:

答案 0 :(得分:16)

没有这样的规则 始终使用{{1>} 通用引用。相反,使用通用引用在函数中使用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"})
  • 范围是一个通用引用是好的,这样调用者就可以使用 foreach 和一个临时容器和一个动作,这就是调用元素上的非const 成员函数。
  • 动作通用引用是件好事,因此调用者可以将可变lambda表达式作为动作传递。
  • 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); } } 用于范围或用于操作是错误的。

答案 1 :(得分:10)

假设f被称为这样:

f(someType{});

如果f的正文在x

上执行某种操作
foo(x);

foo

有两个重载
void foo(someType const&);

void foo(someType&&);

不使用std::forward,因为x是左值,称为以下重载

void foo(someType const&);

可能会让您进行潜在的优化。

使用

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

确保选择了foo的正确重载。

答案 2 :(得分:6)

有名字的东西是左值。这意味着在函数体中,t是左值。如果通用引用最终作为左值引用或作为右值引用,则无关紧要。如果它被命名,它就是一个左值。

如果您直接传递该参数,则将传递左值。

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

总是通过左值的代码可能会受到性能视角的影响但我会说在考虑这个特定问题时你可以忽略它。不总是传递左值有一个更紧迫的问题:复制某些类型可能很昂贵,而其他一些类型根本不能复制,如std::unique_ptr。对于那些在转发时保留rvalueness的类型不是性能问题,而是让代码甚至编译。

答案 3 :(得分:0)

您不应多次转发变量。