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

Vin*_*ent 10 c++ perfect-forwarding c++11 universal-reference

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

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

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

nos*_*sid 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
}
Run Code Online (Sandbox Code Playgroud)

如果使用此函数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);
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 范围是一个通用引用是好的,这样调用者就可以将foreach与临时容器和动作一起使用,这就是在元素上调用非const成员函数.
  • 动作是一个通用引用是好的,这样调用者就可以将一个可变的lambda表达式作为动作传递.
  • 这将是错误的使用std::forward范围行动.


use*_*267 10

让我们说这样f叫:

f(someType{});
Run Code Online (Sandbox Code Playgroud)

如果身体f执行某种操作x

foo(x);
Run Code Online (Sandbox Code Playgroud)

并且有两个重载 foo

void foo(someType const&);

void foo(someType&&);
Run Code Online (Sandbox Code Playgroud)

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

void foo(someType const&);
Run Code Online (Sandbox Code Playgroud)

这可能会花费你潜在的优化.

运用

foo(std::forward<T>(x));
Run Code Online (Sandbox Code Playgroud)

确保选择正确的重载foo.


R. *_*des 6

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

如果您因此直接传递该参数,则将传递左值.

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

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