C ++ 11 std :: forward_as_tuple and std :: forward

Should I std::forward my function parameters when I use them as arguments for 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 links, but is there anything else I should consider?

+5
source share
3 answers

You should use std::forward to keep the category of argument (s) values ​​up to fn() . Since the arguments have a name inside 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 arguments to bar2 , once with std::forward and once without it. Now call them with the argument lvalue and rvalue.

 foo f; bar1(f); std::cout << "--------\n"; bar1(foo{}); 

Conclusion:

 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 using std::forward argument is passed as lvalue to bar2 .

+4
source

Yes, if you want to maintain perfect forwarding semantics. In your example:

 template<class ... List> void fn(List&& ... list) 

the List&& type, where List is actually a template parameter, is a Universal Reference , not an r-value reference. Thus, you must std::forward them to use the function std::forward_as_tuple , otherwise inside the std::forward_as_tuple links r-values ​​passed to fn will be displayed as links to l-value due to spelling of links.

0
source

Yes, you almost certainly want to use std::forward here, this assumes that the arguments in list not used after the call to call_fn . This is a typical use case for std::forward , since you want to use perfect forwarding semantics .

std::forward saves the category of values ​​of its arguments (i.e. lvalues ​​as lvalues, rvalues ​​as rvalues). std::forward_as_tuple in turn will do the same as if std::tuple<List&&...>(std::forward<List>(list)...) was called.

A note on "stored as rvalue references". It’s not that the list arguments in the parameter package are all rvalues ​​links (they can be), but list is displayed in this context, so reverse collapse will be applied, and the type deduced may be rvalue links or links to lvalue. When creating std::tuple this is the distinction you would like to keep / save.

0
source

Source: https://habr.com/ru/post/1200839/


All Articles