Search code examples
c++moveforward

move vs forward on universal references


I was trying out a program on universal references by applying std::move and std::forward on them. Until today I assumed that both were the same but in this very program (given below) the output amazed me.

#include <iostream>
#include <string>
#include <utility>
using namespace std;

class X
{
    string take="";
    public:
    template<class T>
    void pass1 (T &&str)   // str is a universal reference as it can bind to anything, both rvalue and lvalue references
    {
        take=move(str);
    }
    template<class T>
    void pass2 (T &&str)
    {
        take=forward<T>(str);
    }
    void show()
    {
        cout<<"take = "<<take<<"\n";
    }
}obj;

int main()
{
    cout<<"using move on universal reference:-\n";
    string str="he is there";
    cout<<"str = "<<str<<'\n';
    obj.pass1(str);
    obj.show();
    if (str.empty())
    cout<<"str is empty\n\n";
    else
    cout<<"str isnt empty\n\n";
    cout<<"using forward on universal reference:-\n";
    str="he was there";
    cout<<"str = "<<str<<'\n';
    obj.pass2(str);
    obj.show();
    if (str.empty())
    cout<<"str is empty\n\n";
    else
    cout<<"str isnt empty\n\n";
    return 0;
}

Output:

using move on universal reference:-
str = he is there
take = he is there
str is empty

using forward on universal reference:-
str = he was there
take = he was there
str isnt empty
*/

My questions are:

  1. Why are the outputs different?
  2. Don't move and forward work similarly? How are they working differently (in context with the above code)?

Solution

  • Universal references mean that they can bind with apparently anything, both rvalues and lvalues. move & forward donot MOVE ANYTHING LITERALLY and rather perform casts ie they cast the argument to an rvalue. The difference is that move casts unconditionally whereas forward will cast conditionally: it casts to an rvalue only if its argument was initialized with an rvalue. So move always casts whereas forward casts sometimes. Hence the forward in the above case doesn't empty the string as an lvalue (ie str) was passed so it FORWARDED str as an lvalue.