Search code examples
c++templatesforwarding

Using std::forward with a forwarding reference


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?


Solution

  • 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.