Should I std::forward
my function parameters when I use them as arguments to std::forward_as_tuple
?
template<class ... List>
void fn(List&& ... list){
// do I need this forward?
call_fn( forward_as_tuple( forward<List>(list)... ) );
}
I know that they will be stored as rvalue references, but is there anything else I should consider?
You must use std::forward
in order to preserve the value category of the argument(s) to fn()
. Since the arguments have a name within fn
, they are lvalues, and without std::forward
they will always be passed as such to std::forward_as_tuple
.
The difference can be demonstrated using the 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
always passes it arguments on to bar2
, once with std::forward
and once without. Now let's call them with an lvalue and an rvalue argument.
foo f;
bar1(f);
std::cout << "--------\n";
bar1(foo{});
Output:
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
As you can see from the output, in both cases, without the use of std::forward
, the argument is being passed as an lvalue to bar2
.