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)
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
.
有名字的东西是左值.这意味着在函数体中,t
是一个左值.通用引用最终是左值引用还是右值引用无关紧要.如果它被命名,那就是左值.
如果您因此直接传递该参数,则将传递左值.
在您想要将不透明参数传递给另一个函数的情况下,您希望完全按原样传递它.如果它是左值,你想把它作为左值传递; 如果它是一个右值,你想传递一个右值.如所解释的,通过它直接并将其作为左值总是.forward
是否需要将它作为正确的价值传递给它,
始终通过左值的代码可能会遇到性能视角但我会说在考虑这个特定问题时你可以忽略它.有不总是通过一个左一个更为紧迫的问题:复制某些类型可能是昂贵的,一些其他类型的不可复制的所有像std::unique_ptr
.对于那些在转发时保留rvalueness的类型不是性能问题,而是让代码甚至编译.