当我将它们用作std::forward
的参数时,我应该std::forward_as_tuple
我的函数参数吗?
template<class ... List>
void fn(List&& ... list){
// do I need this forward?
call_fn( forward_as_tuple( forward<List>(list)... ) );
}
我知道它们将被存储为右值引用,但还有什么我应该考虑的吗?
答案 0 :(得分:6)
您必须使用std::forward
才能将参数的值类别保留为fn()
。由于参数的名称在fn
之内,因此它们是左值,如果没有std::forward
,它们将始终传递给std::forward_as_tuple
。
可以使用following example:
来证明差异template<typename T>
void bar2(T&& t)
{
std::cout << __PRETTY_FUNCTION__ << ' '
<< std::is_rvalue_reference<decltype(t)>::value << '\n';
}
template<typename T>
void bar1(T&& t)
{
std::cout << __PRETTY_FUNCTION__ << ' '
<< std::is_rvalue_reference<decltype(t)>::value << '\n';
bar2(std::forward<T>(t));
bar2(t);
}
bar1
始终将参数传递给bar2
,一次使用std::forward
,一次不使用foo f;
bar1(f);
std::cout << "--------\n";
bar1(foo{});
。现在让我们用左值和右值参数调用它们。
void bar1(T&&) [with T = foo&] 0
void bar2(T&&) [with T = foo&] 0
void bar2(T&&) [with T = foo&] 0
--------
void bar1(T&&) [with T = foo] 1
void bar2(T&&) [with T = foo] 1
void bar2(T&&) [with T = foo&] 0
输出:
std::forward
正如您在输出中看到的那样,在不使用bar2
的情况下,参数将作为左值传递给{{1}}。
答案 1 :(得分:1)
是的,你几乎肯定想在这里使用std::forward
,这是假设list
中的参数在调用call_fn
后没有使用。 这是std::forward
的典型用例,因为您希望使用完美转发的语义。
std::forward
preserves the value category其论点(即左值为左值,左值为右值)。 std::forward_as_tuple
反过来也会这样做,就像调用std::tuple<List&&...>(std::forward<List>(list)...)
一样。
关于“存储为右值参考”的注释。并不是参数包中的参数List
都是rvalues引用(它们可能是),但是在此上下文中推导出List
,因此将应用引用折叠和推导类型(s )可以是右值引用或左值引用。在创建std::tuple
期间,您希望维护/保留这种区别。
答案 2 :(得分:0)
是的,如果你想保留完美的转发语义。在您的示例中:
template<class ... List>
void fn(List&& ... list)
类型List&&
,其中List
实际上是模板参数,是Universal Reference而不是r值引用。因此,您应std::forward
将它们转换为std::forward_as_tuple
函数,否则在std::forward_as_tuple
内传递给fn
的r值引用将作为l值引用显示,因为引用塌陷。