Search code examples
c++perfect-forwarding

How can anything possibly bind to this forward function?


I think I'm getting awfully close to understanding this. It seems that there are two overloads for the forward function, and I thought two overloads are needed to make it work, but as far as I can see one of them is completely useless, and it works with just one:

template <typename T>
T&& forward(T&& arg)
{// Never gets called.
    // I can't see how since every argument from another function is always
    // an lvalue, nothing can bind to it
    return static_cast<T&&>(arg); 
}

template <typename T>
T&& forward(T& arg)
{// Just this one seems to do the job
    return static_cast<T&&>(arg);
}

template <typename Type>
void emplace(Type&& arg)
{
    forward<Type>(arg);
}

int main()
{
    int a = 0;
    int& intref = a;
    
    emplace(a);
    emplace(int());
}

Both call the one forward function, the other one can go, right?


Solution

  • For illustration, you can change the code to this:

    #include <iostream>
    
    template <typename T>
    T&& forward(T&& arg)
    {   
        // gets called when the parameter is a rvalue reference
        std::cout << "called\n";
        return static_cast<T&&>(arg); 
    }
    
    template <typename T>
    T&& forward(T& arg)
    {
        return static_cast<T&&>(arg);
    }
    
    template <typename Type>
    void emplace(Type&& arg)
    {
        forward<Type>(forward<Type>(arg));
    }
    
    int main()
    {
        emplace(int());
    }
    

    To get output:

    called
    

    In emplace the call forward<Type>(arg); does not call T&& forward(T&& arg) because arg in emplace is not a rvalue reference, sloppy speaking, because it has a name. You can call void emplace(Type&& arg) with an rvalue, but the argument arg isn't one. Actually thats the reason std::forward is needed in the first place.