Why does std::forward have two overloads?

后端 未结 1 866
遥遥无期
遥遥无期 2020-12-10 12:05

Given the following reference collapsing rules

  • T& & --> T&
  • T&& & --> T&
相关标签:
1条回答
  • A good place to start would be Howard Hinnant's answer and paper on std::forward().


    Your implementation handles all the normal use-cases correctly (T& --> T&, T const& --> T const&, and T&& --> T&&). What it fails to handle are common and easy-to-make errors, errors which would be very difficult to debug in your implementation but fail to compile with std::forward().

    Given these definitions:

    struct Object { };
    
    template <typename T, typename = std::enable_if_t<!std::is_const<T>::value>>
    T&& my_forward(const typename std::remove_reference<T>::type& val) {
        return static_cast<T&&>(const_cast<T&&>(val));
    }
    
    template <class T>
    void foo(T&& ) { }
    

    I can pass non-const references to const objects, both of the lvalue variety:

    const Object o{};
    foo(my_forward<Object&>(o));    // ok?? calls foo<Object&>
    foo(std::forward<Object&>(o));  // error
    

    and the rvalue variety:

    const Object o{};
    foo(my_forward<Object>(o));    // ok?? calls foo<Object>
    foo(std::forward<Object>(o));  // error
    

    I can pass lvalue references to rvalues:

    foo(my_forward<Object&>(Object{}));   // ok?? calls foo<Object&>
    foo(std::forward<Object&>(Object{})); // error
    

    The first two cases lead to potentially modifying objects that were intended to be const (which could be UB if they were constructed const), the last case is passing a dangling lvalue reference.

    0 讨论(0)
提交回复
热议问题