Is this function
template< typename T >
void foo( T&& in )
{
bar( std::forward<T>( in ) );
}
equivalent to
template< typename T >
void foo( T&& in )
{
bar( std::forward<T&&>( in ) );
}
where a forwarding reference T&&
is passed to std::forward
?
Yes, those are equivalent, but the idiomatic way is to use plain T
.
Here are how the forward
functions templates are defined in C++14:
1)
template< class T >
constexpr T&& forward( typename std::remove_reference<T>::type& t ) noexcept;
2)
template< class T >
constexpr T&& forward( typename std::remove_reference<T>::type&& t ) noexcept;
First, let's modify your example a bit to make the types less confusing:
template< typename U >
void foo( U&& in )
{
using T = U; // or U&&
bar( std::forward<T>( in ) );
}
Now, let's consider the return type of forward
- T&&
, int
used as example:
| U | T | T&& |
| int | int | int&& |
| int& | int& | int& && = int& |
| int&& | int&& | int&& && = int&& |
and with using T = U&&
| U | U&& (also T) | T&& |
| int | int&& | int&& && = int&& |
| int& | int& && = int& | int& && = int& |
| int&& | int&& && = int&& | int&& && = int&& |
So, the result types are the same.
As for the parameters, typename std::remove_reference<T>::type
is a dead giveaway. I'm using remove_ref<T>
for readability:
| T | remove_ref<T> | remove_ref<T>& | remove_ref<T>&& |
| int | int | int& | int&& |
| int& | int | int& | int&& |
| int&& | int | int& | int&& |
As you can see, this isn't dependant on the reference-ness of the template parameter at all.
Reference collapsing is explained more in-depth here.