Search code examples
c++c++11perfect-forwardinguniversal-reference

What kind of problems for not forwarding universal reference?


As far as I know, in C++11, universal reference should always be used with std::forward, but I am not sure of what kind of problem can occur if std::forward is not used.

template <T>
void f(T&& x);
{
    // What if x is used without std::forward<T>(x) ?
}

Could you provide some illustrations of problems that could occur in this situation ?


Solution

  • There is no such rule to always use std::forward with universal references. On the contrary, it can be dangerous to use std::forward all over the place in functions with universal references. Take a look at the following example:

    template <typename T>
    auto make_pair(T&& t)
    {
        return std::make_tuple(std::forward<T>(t), std::forward<T>(t)); // BAD
    }
    

    If you call this function with make_pair(std::string{"foobar"}), the result is counter-intuitive, because you move from the same object twice.


    Update: Here is another example to show, that it really makes sense to use universal references without perfect forwarding:

    template <typename Range, typename Action>
    void foreach(Range&& range, Action&& action)
    {
        using std::begin;
        using std::end;
        for (auto p = begin(range), q = end(range); p != q; ++p) {
            action(*p);
        }
    }
    
    • It's good that range is a universal reference, so that the caller can use foreach with a temporary container and an action, that's calls a non-const member function on the elements.
    • It's good that action is a universal reference, so that the caller can pass a mutable lambda expression as action.
    • And it would be wrong to use std::forward for range or for action.