3

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?

abraham_hilbert
  • 2,221
  • 1
  • 13
  • 30

1 Answers1

1

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.

Community
  • 1
  • 1
krzaq
  • 16,240
  • 4
  • 46
  • 61